Как применить несколько стилей в WPF
Беа Столльниц a good blog post рассказала style об использовании для этого .net-framework расширения разметки под заголовком .net «Как установить несколько dot-net стилей в WPF?»
Этот блог мертв, поэтому styles я воспроизводю его здесь:
WPF styles и Silverlight предлагают dotnet возможность наследовать стиль styles из другой стиль через свойство .net «BasedOn». Эта функция позволяет разработчикам styles организовать свои стили, используя .net-framework иерархию, подобную классу наследование. Обратите dotnet внимание на следующие стили:
С styles этим синтаксисом кнопка, использующая wpf RedButtonStyle, будет иметь dotnet свой Для свойства Foreground .net-framework установлено значение Red, а .net для свойства Margin - значение wpf 10.
Эта функция уже давно wpf присутствует в WPF, а в Silverlight style 3.
Что делать, если вы хотите .net-framework установить более одного стиля dotnet для элемента? Ни WPF и Silverlight .net не предлагает готового решения .net-framework этой проблемы. К счастью, есть .net-framework способы реализовать это поведение styles в WPF, которые я обсудим style в этом сообщении в блоге.
WPF styles и Silverlight используют styles расширения разметки для предоставления dotnet свойств с значения, для получения .net которых требуется некоторая .net логика. Расширения разметки styles легко узнаваемый по наличию style фигурных скобок, окружающих .net их в XAML. Например, расширение .net-framework разметки {Binding} содержит .net-framework логику для получать значение wpf из источника данных и обновлять .net-framework его при возникновении изменений; в Расширение style разметки {StaticResource} содержит styles логику для получения значения styles из словарь ресурсов на основе .net ключа. К счастью для нас, WPF dotnet позволяет пользователи могут dot-net писать свои собственные расширения dotnet разметки. Эта функция не пока dot-net присутствует в Silverlight, поэтому .net решение в этом блоге - только применимо dot-net к WPF.
Others написали отличные wpf решения для объединения двух styles стилей с помощью разметки расширения. Однако .net мне нужно было решение, которое dot-net позволяло бы объединить неограниченное .net количество стилей, что немного styles сложнее.
Написать расширение styles разметки несложно. Первый wpf шаг - это создать класс, производный .net-framework от MarkupExtension, и использовать MarkupExtensionReturnType, чтобы dotnet указать, что вы намереваетесь значение, возвращаемое dot-net расширением разметки, должно styles иметь тип Style.
[MarkupExtensionReturnType(typeof(Style))] public class MultiStyleExtension : MarkupExtension { }
Указание входных данных для расширения разметки
Мы хотим wpf дать пользователям нашего .net расширения разметки простой wpf способ укажите стили для .net объединения. По сути, есть .net два пути в который пользователь .net может указать входные данные dot-net для расширения разметки. Пользователь styles может установить свойства style или передать параметры конструктору. Поскольку .net в этом сценария пользователю style нужна возможность указать wpf неограниченное количество стилей, мой styles первый подход заключался .net-framework в создании конструктора, который dotnet принимает любые количество styles строк с использованием ключевого dot-net слова params:
public MultiStyleExtension(params string[] inputResourceKeys) { }
Моей целью было .net написать входные данные следующим dotnet образом:
Обратите внимание dotnet на запятую, разделяющую клавиши dot-net разных стилей. К несчастью, пользовательские dot-net расширения разметки не поддерживают styles неограниченное количество параметры dot-net конструктора, поэтому такой .net подход приводит к ошибке .net-framework компиляции. Если бы я знал wpf заранее, сколько стилей хочу dot-net объединить, я мог бы использовал style тот же синтаксис XAML с конструктором, принимающим dotnet желаемое число строк:
public MultiStyleExtension(string inputResourceKey1, string inputResourceKey2) { }
В качестве style обходного пути я решил, что dotnet параметр конструктора принимает единственная wpf строка, определяющая имена wpf стилей, разделенные пробелами. В синтаксис styles неплохой:
private string[] resourceKeys; public MultiStyleExtension(string inputResourceKeys) { if (inputResourceKeys == null) { throw new ArgumentNullException("inputResourceKeys"); } this.resourceKeys = inputResourceKeys.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (this.resourceKeys.Length == 0) { throw new ArgumentException("No input resource keys specified."); } }
Расчет вывода расширения разметки
Чтобы рассчитать dotnet результат расширения разметки, нам style нужно переопределить метод styles из MarkupExtension под названием style «ProvideValue». Возвращенное dot-net значение из этого метода dot-net будет установлен в цели расширения .net разметки.
Я начал с создания dot-net метода расширения для Style, который dotnet знает, как объединить два dot-net стиля. Код этого метода довольно dotnet прост:
public static void Merge(this Style style1, Style style2) { if (style1 == null) { throw new ArgumentNullException("style1"); } if (style2 == null) { throw new ArgumentNullException("style2"); } if (style1.TargetType.IsAssignableFrom(style2.TargetType)) { style1.TargetType = style2.TargetType; } if (style2.BasedOn != null) { Merge(style1, style2.BasedOn); } foreach (SetterBase currentSetter in style2.Setters) { style1.Setters.Add(currentSetter); } foreach (TriggerBase currentTrigger in style2.Triggers) { style1.Triggers.Add(currentTrigger); } // This code is only needed when using DynamicResources. foreach (object key in style2.Resources.Keys) { style1.Resources[key] = style2.Resources[key]; } }
В соответствии с приведенной styles выше логикой первый стиль .net-framework изменяется для включения .net всех информация со второго. Если wpf есть конфликты (например, оба wpf стиля есть сеттер для того wpf же свойства), второй стиль styles побеждает. Уведомление что style помимо копирования стилей styles и триггеров, я также учел значения styles TargetType и BasedOn, а также style любые ресурсы во втором стиль dotnet может иметь. Для TargetType dotnet объединенного стиля я использовал какой .net-framework бы тип ни был более производным. Если .net-framework у второго стиля есть BasedOn style, я .net-framework рекурсивно объединяю его .net иерархию стилей. Если есть ресурсы, я .net-framework копирую их в первый стиль. Если .net эти ресурсы упоминаются с dotnet помощью {StaticResource}, они .net-framework статически разрешаются до этот .net-framework код слияния выполняется, поэтому dotnet нет необходимости перемещать их. Я styles добавил этот код на случай, если wpf мы используем DynamicResources.
Показанный dot-net выше метод расширения включает style следующий синтаксис:
style1.Merge(style2);
Этот .net синтаксис полезен при условии, что styles у меня есть экземпляры обоих .net стилей. в ProvideValue. Ну, нет. Все, что .net я получаю от конструктора, это список styles строковых ключей для этих dotnet стилей. Если бы была поддержка params dotnet в параметрах конструктора, я dotnet мог бы использовать следующие синтаксис wpf для получения фактических styles экземпляров стиля:
public MultiStyleExtension(params Style[] styles) { }
Но это .net не работает. И даже если wpf ограничения параметров не wpf существовало, мы, вероятно, столкнемся dot-net с другим ограничением расширений dotnet разметки, где нам пришлось styles бы использовать синтаксис dotnet элемента свойства вместо styles атрибута синтаксис для указания wpf статических ресурсов, который wpf является подробным и громоздкий styles (я лучше объясню эту ошибку .net в previous blog post). И даже если бы обоих wpf этих ограничений не существовало, я dot-net бы все равно предпочел напишите styles список стилей, используя styles только их названия - он короче dot-net и читать проще, чем StaticResource styles для каждого из них.
Решение style - создать StaticResourceExtension dotnet с помощью кода. Данный ключ dotnet стиля строки типа и поставщика style услуг, я могу использовать StaticResourceExtension, чтобы styles получить фактический экземпляр style стиля. Вот синтаксис:
Style currentStyle = new StaticResourceExtension(currentResourceKey).ProvideValue(serviceProvider)
как style стиль;
Теперь у нас есть все wpf необходимое для написания .net-framework метода ProvideValue:
public override object ProvideValue(IServiceProvider serviceProvider) { Style resultStyle = new Style(); foreach (string currentResourceKey in resourceKeys) { Style currentStyle = new StaticResourceExtension(currentResourceKey).ProvideValue(serviceProvider)
как стиль;
if (currentStyle == null) { throw new InvalidOperationException("Could not find style with resource key " + currentResourceKey + "."); } resultStyle.Merge(currentStyle); } return resultStyle; }
Вот .net-framework полный пример использования .net-framework разметки MultiStyle. расширение:
.net
wpf
styles
Как применить несколько стилей в WPF
Мы используем файлы cookies для улучшения работы сайта. Оставаясь на нашем сайте, вы соглашаетесь с условиями использования файлов cookies. Чтобы ознакомиться с нашими Положениями о конфиденциальности и об использовании файлов cookie, нажмите здесь.