Pull to refresh

Comments 30

У кнопки есть свойство Content. В нем размещаете StackPanel, в ней Image и Text. Все. Зачем такие сложности?
А теперь попробуйте в шаблоне этой кнопки сделать так, чтобы иконка увеличивала свой размер при наведении фокуса.
И что будет? Совершенно не вижу проблемы.

PS: >>После первых же экспериментов стало очевидно, что XAML и иконки в виде png – вещи несовместимые. Не буду долго растекаться почему так – литературы на эту тему хватает

Какой-то бред, если и возникают проблемы — смотрите RenderOptions.BitmapScalingMode\UseLayoutRounding
Можно попросить пример, в котором:
1. 2 кнопки на форме будут созданы первым способом
2. Будет использована иконка png
3. В шаблоне кнопки (в одном месте, без дубляжа на каждой форме) будет задано увеличение иконки (именно иконки, не текста) при наведении фокуса
4. Иконки будут выглядеть без искажений, независимо от накладываемых эффектов

Вдруг я действительно несу бред и это можно сделать намного проще.
Не поленился:
Вот разметка: paste.org.ru/?r7bbx4
Вот скриншот: (я направил курсор на нижнюю кнопку и иконка увеличилась используя анимацию)
image
Да, извиняюсь что не уточнил, но думал что это само собой разумеется — интересуют разные иконки на кнопках.
Ну тогда да, я бы отнаследовался от Button добавив dp Icon. Ну и привязал бы Source playImage на это свойство через RelativeSource FindAncestor (если так уж не хочется переопределять весь Template).
В целом можно не наследоваться и привязаться к свойству Tag. Должно сработать.

Автору — статья ниочем. Жду «6 вариантов CheckedListBox и все говно», и аналогичную с RadioListBox.
Надеюсь вы прочли статью до конца?
Расскажите как через Tag указать размер иконки и ориентацию StackPanel.
Это кроме того, что Tag — вообще мусорное свойство, и им пользуются все кому не лень. Завтра в проект придет студент, который покладёт в Tag какой-нибудь контекст, и вся кнопка на этом закончится.
Я смотрю вы меня раскусили. Разумеется не читал, ведь после такого:
>>опишу минусы – содержимое кнопки придется задавать из конструктора наследника, на C#
я бросил читать, ибо это бред быдлокодера

Для начала стоит четко определить что необходимо от кнопки (слышали про ТЗ?). А то я смотрю вам не угодить. В комментарии выше:

>>1. 2 кнопки на форме будут созданы первым способом…
Nagg предложил очень простой вариант, удовлетворяющий по всем пунктам.

Но тут вылез сами знаете кто:
>>Да, извиняюсь что не уточнил, но думал что это само собой разумеется — интересуют разные иконки на кнопках.

Ок, и с этим разобрались. Но вот незадача, в тред опять врывается он:
>>Надеюсь вы прочли статью до конца? Расскажите как через Tag указать размер иконки и ориентацию StackPanel.

Так и хочется написать через жопу. Но ладно, вернемся к делу.

>>Это кроме того, что Tag — вообще мусорное свойство, и им пользуются все кому не лень. Завтра в проект придет студент, который покладёт в Tag какой-нибудь контекст, и вся кнопка на этом закончится.
Пишите контрол, в таком случае. Как вариант не пускать криворуких студентов.
Откуда столько ненависти и ярлыков?
Nagg предложил вариант, в котором на каждой кнопке одна и та же иконка. Сколько интерфейсов такого рода вы встречали?
Я предпочитаю не плодить лишних сущностей и максимум интерфейса программировать через XAML. Наследники от кнопок, наследники от чекбоксов, наследники от всего — и весь проект у вас в наследниках. В случае использования AttachedProperty достаточно создать всего один класс Ext с тремя методами и по 1 шаблону на каждый тип контрола.
Не хочется начинать срач о быдлокоде (мне кажется я до сих пор был корректен), но вешать базовый интерфейсный функционал на Tag — это зло.
Мне не кажется, что это намного более простой вариант. Просто еще один хитрый способ.
Вместо одно Extension и одного шаблона дерибаним код на наследника от кнопки, шаблон содержимого и шаблон самой кнопки. Три сущности вместо двух.
Для тех кто не смотрел код этого решения.
Автор поспешил и по сути повторил промежуточный шаг из статьи. С помощью этого кода можно получить только вот такую картинку (из статьи):

А указать разные иконки для кнопок таким способом невозможно, так как иконка задана прямо в шаблоне.
Для этого следует использовать Triggers.
Зачем воротить лишний код, если поведение состояний — это одна из базовых функций шаблона.
Все зависит от того, что вам нужно.

Мы для анимаций со сменой иконок, плавными переходами цветов используем EventTriggers.
Видимо для того, чтобы один раз сделал и используешь стили везде где потребуется и не тратить время на кучу костылей. Опять же когда наберется библиотека стилей что-либо новое создать становится очень легко и быстро.
но тот факт что за два дня поисков я не нашел более приемлемой бесплатной реализации говорит о том, что на этом фронте не всё ладно.

Контрол по первой вашей ссылке чем не понравился?
Ну с чего начать?
Кнопка перестает быть единым контролом. Например Нельзя в едином шаблоне задать анимацию кнопки при наведении фокуса. Реализовать анимацию можно, но только уже через код самой формы, а это дубляж кода. При необходимости чуть-чуть поменять стиль всех кнопок в приложении получаем копипаст и мороку. А этот подход достаточно реализовать один раз, и весь функционал кнопки остается на месте.
Для быстрого решения проблемы лучше первый вариант.
Для всего остального, доведенные до ума второй вариант. Лично у меня это выглядит примерно так:

<control:Button Height="75" Grid.Row="1" Margin="0" Icon="/icons/lens.png" IconMargin="4"/>

Не каких проблем с использованием или реализацией не испытываю. Настраивать могу все что душе угодно.
Лично для меня это более удобный и привычный вариант.
Слишком много ни о чем. Было бы лучше, если автор написал какую проблему решает и способы ее решения. Кнопка с картинкой это не проблема.
Ну проблема в общем-то проста и стандартна, не думал что стоит ее описывать:
— написать приложение, в котором присутствуют кнопки с иконками;
— стили для контролов приложения должны задаваться через шаблоны, не более одного шаблона для контрола каждого типа;
— в зависимости от функции кнопки (тулбар, диалоговая кнопка и т.д.) текст может располагаться как под иконкой, так и сбоку, а сами иконки могут быть разных размеров;
— минимизировать количество кода, описывающего конкретную кнопку, чтобы не раздувать XAML формы.
Идеологически верное решение будет выглядеть так:

Наследуем наш контрол (IconButton) от ContentControl, добавляем свойства Icon/IconTemplate по образу и подобию Content/ContentTemplate, добавляем другие полезные свойства от кнопки (реализуем интерфейс ICommandSource), в стиле по умолчанию (Themes\Generic.xaml) используем обычную Button, внутрь которого помещаем два ContentPresenter (один для Icon, второй для Content), привязываем кнопочные свойства из ICommandSource. Всё!

Используем так (иконки оформляем как DataTemplate во избежание многих проблем):

<IconButton IconTemplate="{StaticResource IconTriangle}" Content="Привет!" Command="{Binding MyFancyCommand}" />
внутрь которого помещаем два ContentPresenter (один для Icon, второй для Content)

А можно примерчик привести такого стиля по умолчанию?

Просто я считал, что ContentPresenter используется для указания в шаблоне значения свойства контрола Content. А для чего нужен второй ContentPresenter? Чем это лучше использования Image для описания иконки в шаблоне?

Буду весьма благодарен за разъяснение.
Такой подход намного гибче и универсальнее использования Image. Я потом могу использовать в качестве иконки и Image, и Path и даже TextBlock со шрифтом Webdings. ContentPresenter нужен для встраивания в визуальное дерево контрола пользовательского контента, по умолчанию он просто привязывается к Content/ContentTemplate.

Шаблон контрола будет выглядеть примерно так:

<ControlTemplate TargetType="IconButton">
 <Button Command="{TemplateBinding Command}"
     CommandParameter="{TemplateBinding CommandParameter}"
     Margin="0"
     Padding="0"
     HorizontalAlignment="Stretch">
  <Grid>
   <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="*" />
   </Grid.ColumnDefinitions>

   <ContentPresenter Grid.Column="0"
            Content="{TemplateBinding Icon}"
            ContentTemplate="{TemplateBinding IconTemplate}"
            HorizontalAlignment="Left"
            VerticalAlignment="Center"
            Margin="10,0,0,0" />

   <ContentPresenter Grid.Column="1"
            Content="{TemplateBinding Content}"
            ContentTemplate="{TemplateBinding ContentTemplate}"
            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
            Margin="{TemplateBinding Padding}" />

  </Grid>
 </Button>
</ControlTemplate>
Content="{Binding (Ext:E.Icon), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"

Зачем так делать? А если у меня кнопка в кнопке лежит что мне делать? правильный вариант в ControlTemplate выглядит вот так

Content="{TemplateBinding (Ext:E.Icon)}"

ну или вот так, если хочется чтобы автоматическая конвертация работала

Content="{Binding (Ext:E.Icon), RelativeSource={RelativeSource TemplatedParent}}"
Спасибо за дельное замечание. Кнопка в кнопке — это, конечно же, та еще экзотика но по существу так чище.
С PNG нету никаких проблем, просто нужно использовать иконки с запасом размера (желательно кратным отображаемому) под увеличение, а размеры самого элемента, который показывает изображение, уже надо задавать отдельно. При использовании UseLayoutRounding/SnapsToDevicePixels четкость хорошая.
Векторные иконки — это очень плохая идея. WPF по умолчанию не кеширует результаты растеризации векторной геометрии, и пользователи с отсутствием аппаратной поддержки механизмов растеризации будут иметь серьёзные проблемы с производительностью при большом одновременном количестве отображаемых векторных иконок в кадре. Каждый экземпляр такой иконки тесселируется и растеризуется по отдельности. Не каждый кадр, но тогда, когда область иконки попадает в «грязный регион» при изменении содержимого окна. Т.е. при любом изменении цвета подложки кнопки. Так-же это плохо виляет на энергопотребление, что критично для мобильных устройств, тесселяция в WPF полностью программная. И если для тесселяции простеньких иконок еще надо произвести не так много вычислений, то сложные иконки с толстой геометрией и большим количеством деталей могут приводить к заметным всплескам процессорной активности в процессе работы пользователя с приложением.
Как вариант можно использовать кеширование композиции — свойство UIElement.CacheMode/класс BitmapCache, но тогда становится непонятно, зачем вообще нужно векторное представление иконки, если выводится предварительно растеризованное изображение, т.е. заменимое обычным изображением, уже растеризованным до этапа компиляции приложения.
Я в последнее время использую очень простые иконки, и та же Metro Studio от SyncFusion — тому хороший пример. Понятно, что не стоит использовать полноцветные векторные копии обычных иконок, смысла большого не имеет. Ну а что насчет интерполяции — если с искажениями при изменении размеров иконки с нею еще можно мириться, то при эффектах покачивания или перспективы искажения уже критичны.
Sign up to leave a comment.

Articles