Намучившись с растровыми изображениями и начитавшись всяких ужасов об их отображении в WPF, я решил перебраться на векторную графику... и с порога столкнулся со следующей задачкой:
Есть ToggleButton. Если она нажата, я хочу, чтобы на ней отображалась одна иконка. Если отжата — другая. Иконки, как уже было помянуто, векторные.
И все бы было ничего, но:
1) В данном варианте я имею 2 иконки — цветную и чернобелую. Обе занимают место и время загрузки. В перспективе кнопок значительно больше. Да и обесцвечивать вручную каждую иконку откровенно лениво.
2) Почему-то, ведет себя эта конструкция очень странно. При изменении состояния одной кнопки, исчезает другая. Если кнопок несколько — исчезают по одной-несколько в произвольном порядке. Аттрибут x:Shared="false" для Viewbox'а не помогает. =\
Подскажите, гуру, как быть в такой ситуации? Что делать? Хочется и корректного переключения, и смены палитры на серую "на лету".
Здравствуйте, EqKeeper, Вы писали:
EK>1) В данном варианте я имею 2 иконки — цветную и чернобелую. Обе занимают место и время загрузки. В перспективе кнопок значительно больше. Да и обесцвечивать вручную каждую иконку откровенно лениво.
Можно использовать шейдерный эффект, типа такого.
EK>2) Почему-то, ведет себя эта конструкция очень странно. При изменении состояния одной кнопки, исчезает другая. Если кнопок несколько — исчезают по одной-несколько в произвольном порядке. Аттрибут x:Shared="false" для Viewbox'а не помогает. =\
Viewbox — не Freezable объект, следовательно он не умеет клонироваться, а потому не сможет присутствовать многократно в разных кнопках. Для чего вообще там Viewbox? Нельзя представить иконку через Geometry?
Здравствуйте, MxMsk, Вы писали:
MM>Здравствуйте, EqKeeper, Вы писали:
EK>>1) В данном варианте я имею 2 иконки — цветную и чернобелую. Обе занимают место и время загрузки. В перспективе кнопок значительно больше. Да и обесцвечивать вручную каждую иконку откровенно лениво. MM>Можно использовать шейдерный эффект, типа такого.
EK>>2) Почему-то, ведет себя эта конструкция очень странно. При изменении состояния одной кнопки, исчезает другая. Если кнопок несколько — исчезают по одной-несколько в произвольном порядке. Аттрибут x:Shared="false" для Viewbox'а не помогает. =\ MM>Viewbox — не Freezable объект, следовательно он не умеет клонироваться, а потому не сможет присутствовать многократно в разных кнопках. Для чего вообще там Viewbox? Нельзя представить иконку через Geometry?
Не знаю. Быть может, и можно.
Я лишь недавно ковыряю WPF, поэтому вывожу так, как получается, стараясь обойтись минимальным объемом кода/xaml'а.
Viewbox использую для того, чтобы ограничить иконку, в противном случае, из-за Canvas в иконках, это чудовище вылезало за отведенные ему границы и плевать хотела на мои Width, MaxWidth, ActualWidth и прочие ограничения. >_>
Изначально вариант был иной — Viewbox я объявлял в ControlTemplate и пытался привязать иконку (ее верхний Canvas) к Child. Оказалось, что это сделать невозможно. Вот и решил пойти другим путем. И он оказался неверен.
Подскажи, пожалуйста, как ее вывести правильно?
Здравствуйте, EqKeeper, Вы писали:
EK>Я лишь недавно ковыряю WPF, поэтому вывожу так, как получается, стараясь обойтись минимальным объемом кода/xaml'а. EK>Viewbox использую для того, чтобы ограничить иконку, в противном случае, из-за Canvas в иконках, это чудовище вылезало за отведенные ему границы и плевать хотела на мои Width, MaxWidth, ActualWidth и прочие ограничения. >_> EK>Изначально вариант был иной — Viewbox я объявлял в ControlTemplate и пытался привязать иконку (ее верхний Canvas) к Child. Оказалось, что это сделать невозможно. Вот и решил пойти другим путем. И он оказался неверен. EK>Подскажи, пожалуйста, как ее вывести правильно?
Выложи сюда полный XAML какой-нибудь из иконок.
Здравствуйте, MxMsk, Вы писали:
MM>Здравствуйте, EqKeeper, Вы писали:
EK>>Я лишь недавно ковыряю WPF, поэтому вывожу так, как получается, стараясь обойтись минимальным объемом кода/xaml'а. EK>>Viewbox использую для того, чтобы ограничить иконку, в противном случае, из-за Canvas в иконках, это чудовище вылезало за отведенные ему границы и плевать хотела на мои Width, MaxWidth, ActualWidth и прочие ограничения. >_> EK>>Изначально вариант был иной — Viewbox я объявлял в ControlTemplate и пытался привязать иконку (ее верхний Canvas) к Child. Оказалось, что это сделать невозможно. Вот и решил пойти другим путем. И он оказался неверен. EK>>Подскажи, пожалуйста, как ее вывести правильно? MM>Выложи сюда полный XAML какой-нибудь из иконок.
Здравствуйте, EqKeeper, Вы писали:
EK>>>Подскажи, пожалуйста, как ее вывести правильно? MM>>Выложи сюда полный XAML какой-нибудь из иконок.
Несколько моментов.
Во-первых, Canvas никак не работает с размерами содержимого. Поэтому, если нужно контролировать размеры, надо использовать другой контейнер, например, Grid. Такие свойства, как Canvas.Top/Canvas.Left придется сымитировать через Margin.
Во-вторых, лучше выразить иконки через Freezable. Это сделает их реюзабельными и более быстрыми. Я не знаю, есть ли средства, автоматизирующие это, но можно потратить время и перевести набор Shape-ов в набор геометрий руками. Благо, свойства имеют почти стопроцентное соответствие. Иконку можно представлять в виде DrawingGroup. Из твоего примера у меня вышло нечто такое:
<DrawingGroup x:Key="SaveIcon">
<GeometryDrawing Brush="{StaticResource linearGradient2269}"
Geometry="M 4.5577604 3.5675797 L 43.448063 3.5675797 C 44.037357 3.5675797 44.511771 4.0419938 44.511771 4.6312883 L 44.511771 42.396499 C 44.511771 42.985793 44.037357 43.460207 43.448063 43.460207 L 6.5577604 43.460207 C 6.5577604 43.460207 3.4940519 40.396499 3.4940519 40.396499 L 3.4940519 4.6312883 C 3.4940519 4.0419938 3.9684659 3.5675797 4.5577604 3.5675797 z">
<GeometryDrawing.Pen>
<Pen Brush="#FF25375F"
MiterLimit="4"
LineJoin="Round"
StartLineCap="Round"
EndLineCap="Round"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Brush="#FFFFFFFF">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="9,4,30,23" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="#FFD31C00">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="9,4,30,4"
RadiusX="0.12620772"
RadiusY="0.12620771"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="#FF000000"
Geometry="M 11 12.5 L 37 12.5">
<GeometryDrawing.Pen>
<Pen Brush="#FF000000"
MiterLimit="4"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Brush="#FF000000"
Geometry="M 11 17.5 L 37 17.5">
<GeometryDrawing.Pen>
<Pen Brush="#FF000000"
MiterLimit="4"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Brush="#FF000000"
Geometry="M 11 22.5 L 37 22.5">
<GeometryDrawing.Pen>
<Pen Brush="#FF000000"
MiterLimit="4"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Geometry="M 4.6189226 4.5276647 L 43.387404 4.5276647 C 43.457323 4.5276647 43.513612 4.5839533 43.513612 4.6538724 L 43.513612 42.302111 C 43.513612 42.37203 43.457323 42.428319 43.387404 42.428319 L 6.9282818 42.428319 C 6.9282818 42.428319 4.4927149 40.036946 4.4927149 40.036946 L 4.4927149 4.6538724 C 4.4927149 4.5839533 4.5490035 4.5276647 4.6189226 4.5276647 z">
<GeometryDrawing.Pen>
<Pen Brush="{StaticResource linearGradient2283}"
MiterLimit="4"
StartLineCap="Round"
EndLineCap="Round"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Brush="{StaticResource linearGradient2348}"
Geometry="M 14.113967 28.562183 L 33.863791 28.562183 C 34.751762 28.562183 35.466627 29.313093 35.466627 30.245836 L 35.466627 43.447387 C 35.466627 43.447387 12.511131 43.447387 12.511131 43.447387 L 12.511131 30.245836 C 12.511131 29.313093 13.225996 28.562183 14.113967 28.562183 z">
<GeometryDrawing.Pen>
<Pen Brush="#FF525252"
MiterLimit="4"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<GeometryDrawing Brush="#FF4967A2">
<GeometryDrawing.Pen>
<Pen Brush="#FF525252"
MiterLimit="4"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="16,30,5,10"
RadiusX="0.75120711"
RadiusY="0.75120765"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
Теперь иконку можно поместить в Image, который потом можно положить в Content кнопки:
Здравствуйте, MxMsk, Вы писали:
MM>Несколько моментов.
MM>Во-первых, Canvas никак не работает с размерами содержимого. Поэтому, если нужно контролировать размеры, надо использовать другой контейнер, например, Grid. Такие свойства, как Canvas.Top/Canvas.Left придется сымитировать через Margin.
MM>Во-вторых, лучше выразить иконки через Freezable. Это сделает их реюзабельными и более быстрыми. Я не знаю, есть ли средства, автоматизирующие это, но можно потратить время и перевести набор Shape-ов в набор геометрий руками. Благо, свойства имеют почти стопроцентное соответствие. Иконку можно представлять в виде DrawingGroup. Из твоего примера у меня вышло нечто такое: MM>[xml]
MM>И тогда никаких Viewbox-ов, никаких Canvas-ов не нужно. А также не будет никакого взаимного влияния разных кнопок друг на друга.
Понятное дело, что иконку писал не руками. Просто открыл в Inkskape SVG'шную и пересохранил в XAML. Твой вариант, конечно, нравится куда больше. Постараюсь его осмыслить!
Благодарю!