Как в WPF применить несколько стилей к a FrameworkElement
? Например, у меня есть элемент управления, который уже имеет стиль. У меня также есть отдельный стиль, который я хотел бы добавить к нему, не выбрасывая первый. Стили имеют разные TargetTypes, поэтому я не могу просто расширить один с другим.
153
Ответы:
Я думаю, что простой ответ заключается в том, что вы не можете сделать (по крайней мере, в этой версии WPF) то, что вы пытаетесь сделать.
То есть для любого конкретного элемента может быть применен только один стиль.
Однако, как уже говорили другие, возможно, вы можете использовать,
BasedOn
чтобы помочь вам. Проверьте следующий кусок рыхлого xaml. В нем вы увидите, что у меня есть базовый стиль, который устанавливает свойство, существующее в базовом классе элемента, к которому я хочу применить два стиля. И во втором стиле, который основан на базовом стиле, я установил другое свойство.Итак, идея здесь ... если вы можете каким-то образом отделить свойства, которые вы хотите установить ... в соответствии с иерархией наследования элемента, для которого вы хотите установить несколько стилей ... у вас может быть обходной путь.
Надеюсь это поможет.
Примечание:
Особо следует отметить одну вещь. Если вы измените
TargetType
во втором стиле (в первом наборе xaml выше) наButtonBase
, эти два стиля не будут применены. Однако, проверьте следующее xaml ниже, чтобы обойти это ограничение. По сути, это означает, что вам нужно дать ключу стиля и связать его с этим ключом.источник
derivedStyle
Должен прийти послеbaseStyle
У Bea Stollnitz было хорошее сообщение в блоге об использовании расширения разметки для этого под заголовком "Как я могу установить несколько стилей в WPF?"
Этот блог уже мертв, поэтому я воспроизводю пост здесь
WPF и Silverlight предоставляют возможность получить стиль из другого стиля через свойство «BasedOn». Эта функция позволяет разработчикам организовывать свои стили, используя иерархию, аналогичную наследованию классов. Рассмотрим следующие стили:
При таком синтаксисе для свойства Button, использующего RedButtonStyle, свойство Foreground будет установлено на Red, а свойство Margin - на 10.
Эта функция уже давно используется в WPF, и она появилась в Silverlight 3.
Что если вы хотите установить более одного стиля для элемента? Ни WPF, ни Silverlight не предлагают решения этой проблемы "из коробки". К счастью, есть способы реализовать это поведение в WPF, о котором я расскажу в этом посте.
WPF и Silverlight используют расширения разметки для предоставления свойств со значениями, для получения которых требуется некоторая логика. Расширения разметки легко узнаваемы по наличию фигурных скобок, окружающих их в XAML. Например, расширение разметки {Binding} содержит логику для извлечения значения из источника данных и его обновления при возникновении изменений; расширение разметки {StaticResource} содержит логику для получения значения из словаря ресурсов на основе ключа. К счастью для нас, WPF позволяет пользователям создавать собственные расширения разметки. Эта функция еще не представлена в Silverlight, поэтому решение в этом блоге применимо только к WPF.
Другие написали отличные решения для объединения двух стилей с использованием расширений разметки. Тем не менее, я хотел решение, которое предоставило бы возможность объединять неограниченное количество стилей, что немного сложнее.
Написать расширение разметки просто. Первым шагом является создание класса, производного от MarkupExtension, и использование атрибута MarkupExtensionReturnType, чтобы указать, что вы хотите, чтобы значение, возвращаемое из расширения разметки, имело тип Style.
Указание входных данных для расширения разметки
Мы хотели бы предоставить пользователям нашего расширения разметки простой способ указать стили для объединения. Существуют два основных способа, которыми пользователь может указать входные данные для расширения разметки. Пользователь может установить свойства или передать параметры конструктору. Поскольку в этом сценарии пользователю нужна возможность указывать неограниченное количество стилей, мой первый подход заключался в создании конструктора, который принимает любое количество строк, используя ключевое слово «params»:
Моя цель состояла в том, чтобы иметь возможность написать входные данные следующим образом:
Обратите внимание на запятую, разделяющую ключи разных стилей. К сожалению, пользовательские расширения разметки не поддерживают неограниченное количество параметров конструктора, поэтому такой подход приводит к ошибке компиляции. Если бы я заранее знал, сколько стилей я хотел бы объединить, я мог бы использовать тот же синтаксис XAML с конструктором, принимающим нужное количество строк:
В качестве обходного пути я решил, что параметр конструктора должен принимать одну строку, которая задает имена стилей, разделенные пробелами. Синтаксис не так уж плох:
Расчет выхода расширения разметки
Чтобы вычислить вывод расширения разметки, нам нужно переопределить метод из MarkupExtension, который называется «ProvideValue». Значение, возвращаемое этим методом, будет установлено в цели расширения разметки.
Я начал с создания метода расширения для стиля, который знает, как объединить два стиля. Код для этого метода довольно прост:
С логикой выше, первый стиль изменяется, чтобы включать всю информацию от второго. Если есть конфликты (например, оба стиля имеют установщик для одного и того же свойства), выигрывает второй стиль. Обратите внимание, что помимо копирования стилей и триггеров, я также принял во внимание значения TargetType и BasedOn, а также любые ресурсы, которые может иметь второй стиль. Для TargetType объединенного стиля я использовал тот тип, который является более производным. Если у второго стиля есть стиль BasedOn, я рекурсивно объединяю его иерархию стилей. Если у него есть ресурсы, я копирую их в первый стиль. Если эти ресурсы упоминаются с помощью {StaticResource}, они статически разрешаются до выполнения этого кода слияния, и поэтому нет необходимости перемещать их. Я добавил этот код на случай, если мы используем DynamicResources.
Метод расширения, показанный выше, включает следующий синтаксис:
Этот синтаксис полезен при условии, что у меня есть экземпляры обоих стилей в ProvideValue. Ну, нет. Все, что я получаю от конструктора, это список строковых ключей для этих стилей. Если бы была поддержка параметров в параметрах конструктора, я мог бы использовать следующий синтаксис для получения реальных экземпляров стиля:
Но это не работает. И даже если бы ограничение params не существовало, мы, вероятно, столкнулись бы с другим ограничением расширений разметки, где нам пришлось бы использовать синтаксис элемента свойства вместо синтаксиса атрибута для указания статических ресурсов, что является многословным и громоздким (я объясняю это ошибка лучше в предыдущем сообщении в блоге ). И даже если бы оба эти ограничения не существовали, я все равно предпочел бы написать список стилей, используя только их имена - он короче и проще для чтения, чем StaticResource для каждого из них.
Решением является создание StaticResourceExtension с использованием кода. Учитывая ключ стиля типа string и поставщика услуг, я могу использовать StaticResourceExtension для получения фактического экземпляра стиля. Вот синтаксис:
Теперь у нас есть все части, необходимые для написания метода ProvideValue:
Вот полный пример использования расширения разметки MultiStyle:
источник
Но вы можете перейти от другого .. взгляните на свойство BasedOn
источник
WPF / XAML изначально не предоставляет эту функциональность, но обеспечивает расширяемость, позволяющую вам делать то, что вы хотите.
Мы столкнулись с той же потребностью и в итоге создали наше собственное расширение разметки XAML (которое мы назвали «MergedStylesExtension»), чтобы позволить нам создать новый стиль из двух других стилей (которые, при необходимости, возможно, могли бы использоваться несколько раз в ряд, чтобы унаследовать от еще большего количества стилей).
Из-за ошибки WPF / XAML нам нужно использовать синтаксис элемента свойства, чтобы использовать его, но в остальном он работает нормально. Например,
Я недавно писал об этом здесь: http://swdeveloper.wordpress.com/2009/01/03/wpf-xaml-multiple-style-inheritance-and-markup-extensions/
источник
Это возможно, создав вспомогательный класс для использования и переноса ваших стилей. Упомянутый здесь CompoundStyle показывает, как это сделать. Есть несколько способов, но проще всего сделать следующее:
Надеюсь, это поможет.
источник
Используйте
AttachedProperty
для установки нескольких стилей, например, следующего кода:Usege:
Результат:
источник
если вы не касаетесь каких-либо определенных свойств, вы можете получить все базовые и общие свойства для стиля, целевым типом которого будет FrameworkElement. затем вы можете создавать специфические варианты для каждого целевого типа, без необходимости повторного копирования всех этих общих свойств.
источник
Вероятно, вы можете получить что-то похожее, если применить это к коллекции элементов с помощью StyleSelector, я использовал это для решения аналогичной проблемы при использовании различных стилей в TreeViewItems в зависимости от типа связанного объекта в дереве. Возможно, вам придется немного изменить класс ниже, чтобы приспособиться к вашему конкретному подходу, но, надеюсь, это поможет вам начать
Затем вы применяете это так
источник
Иногда вы можете подойти к этому, вложив панели. Допустим, у вас есть стиль, который меняет передний план, а другой - FontSize, вы можете применить последний к TextBlock и поместить его в сетку, стиль которой является первым. Это может помочь и может быть самым простым способом в некоторых случаях, хотя и не решит все проблемы.
источник
Когда вы переопределяете SelectStyle, вы можете получить свойство GroupBy через отражение, как показано ниже:
источник
Если вы пытаетесь применить уникальный стиль только к одному элементу в качестве дополнения к базовому стилю, есть совершенно другой способ сделать это, который ИМХО намного лучше для удобочитаемого и поддерживаемого кода.
Очень часто необходимо настроить параметры для каждого элемента. Определение стилей словаря, предназначенных только для использования с одним элементом, чрезвычайно сложно поддерживать или иметь смысл. Чтобы избежать создания стилей только для одноэлементных настроек, прочитайте мой ответ на мой собственный вопрос здесь:
https://stackoverflow.com/a/54497665/1402498
источник