Я застрял с атрибутами ThemeInfo в моем файле AssemblyInfo.cs. Я пытаюсь написать настраиваемый элемент управления. Пользовательский элемент управления находится в dll под названием «MyCustomControls.dll». Более того, сам элемент управления является производным от другого настраиваемого элемента управления, который находится внутри другой библиотеки DLL под названием «MyAnotherCustomControls.dll».

Я читал в MSDN, что ThemeInfo должен быть объявлен с двумя параметрами, отвечающими за конкретное местоположение темы управления и общее конкретное местоположение, хотя я понятия не имею, что такое «тема», а что «общее». Как мне лучше понять этих двоих?

Если бы кто-нибудь мог объяснить мне пример с нуля, что такое «общее», а что «тематическое». Более того, когда использовать «общий» или «тематический». Как они вообще используются системой WPF? Мне действительно нужно объяснение на простом английском языке, поэтому, пожалуйста, сэкономьте свое время, если вы собираетесь отправить мне ссылку MSDN. Я прочитал документацию msdn о ThemeInfo и не понимаю.

Также может кто-нибудь сказать мне, как с помощью ThemeInfo указать моему "MyCustomControls.dll" использовать ресурсы словаря, определенные в "MyAnotherCustomControls.dll"? Возможно ли это сделать только с помощью ThemeInfo, или мне нужно иметь дело с MergedDirectories в "MyCustomControls.dll"? Я хотел бы, чтобы система WPF позаботилась о размещении ресурсов, чтобы я мог использовать ключи стилей из «MyAnotherCustomControls.dll» без необходимости добавлять объединенный каталог в «MyCustomControls.dll».

2
snowy hedgehog 20 Мар 2013 в 15:40

1 ответ

Лучший ответ

Я читал в MSDN, что ThemeInfo должен быть объявлен с двумя параметрами, отвечающими за конкретное местоположение темы управления и общее конкретное местоположение, хотя я понятия не имею, что такое «тема», а что «общее». Как мне лучше понять этих двоих?

В основном платформа WPF будет искать ресурс xaml, имя которого совпадает с именем темы ОС. Итак, если вы используете XP с синей темой, это будет «luna.normal.xaml». Если он не найдет файл с таким точным именем, он будет искать «generic.xaml». На самом деле я думаю, что они сначала ищут "classic.xaml", если не находят тот, который соответствует конкретной ОС, а затем ищут generic.xaml. Вы можете думать о generic.xaml как о ресурсах по умолчанию.

Атрибут ThemeInfo просто сообщает WPF где определены эти ресурсы. Есть 3 варианта:

  • Нет - вы не предоставляете ни тематических, ни общих ресурсов. Это действительно оптимизация, поэтому фреймворк WPF не утруждает себя их поиском. Обычно вы не используете это для GenericDictionaryLocation , но вы можете использовать это для ThemeDictionaryLocation в случае, если вы не собирались определять ресурсы для конкретной темы ОС (т. Е. Вы не не хочу, чтобы ваш элемент управления выглядел по-разному в разных темах ОС). Обычно поставщики элементов управления определяют словарь ресурсов для каждой возможной темы ОС, чтобы элементы управления выглядели согласованно с другими элементами управления и окнами, работающими в этой операционной системе.
  • ExternalAssembly - это означает, что вы определяете отдельную сборку для ресурсов. Итак, если вы посмотрите на платформу WPF, вы увидите, что они используют ее для сборки PresentationFramework для ThemeDictionaryLocation . Затем они определили отдельную сборку для каждой темы ОС, которую они хотят поддерживать (например, PresentationFramework.Aero.dll, PresentationFramework.Luna.dll и т. Д.). Имя сборки, которую он будет искать, - это имя определяющей сборки плюс имя темы.
  • SourceAssembly - это означает, что ресурсы определены в самой сборке. Итак, в этой сборке у вас будет папка "themes", содержащая словари ресурсов.

Эта статья в MSDN о создании элементов управления действительно не так уж плоха в плане предоставления информация об этом.

Также может кто-нибудь сказать мне, как с помощью ThemeInfo сказать моему "MyCustomControls.dll" использовать ресурсы словаря, определенные в "MyAnotherCustomControls.dll"? Возможно ли это сделать только с помощью ThemeInfo, или мне нужно иметь дело с MergedDirectories в "MyCustomControls.dll"? Я хотел бы, чтобы система WPF позаботилась о поиске ресурсов, чтобы я мог использовать ключи стилей из «MyAnotherCustomControls.dll» без необходимости добавлять объединенный каталог в «MyCustomControls.dll».

Вы не можете использовать ThemeInfo, чтобы сообщить WPF, что он должен искать ваши ресурсы в некоторой произвольной сборке. При этом, если вы не устанавливаете или не переопределяете DefaultStyleKey , как это обычно делается при определении настраиваемого элемента управления, он должен продолжать использовать ресурсы для базового класса, для которого установлен DefaultStyleKey / переопределено для ресурсов по умолчанию.

Однако следует отметить, что локальное разрешение стиля (т. Е. Когда свойство Style вашего элемента управления не установлено, а WPF смотрит из того места, где расположен элемент, и проходит вверх по визуальному / логическому дереву в поисках стиль, который может неявно влиять на этот элемент) будет всегда искать стиль, ключ которого соответствует точному типу класса. Поэтому, если у вас есть стиль, TargetType которого (и, следовательно, ключ по умолчанию, когда он помещен в ResourceDictionary), является TextBox, определенным в ресурсах вашего окна, это повлияет на все экземпляры TextBox в этом окне (если у них нет стиля ближе в визуальном tree - т.е. определяется в ресурсах элемента между собой некоторого предка - или его свойство Style установлено). Однако, если у вас есть класс, производный от TextBox (например, класс MyTextBox: TextBox), он не будет подбирать / использовать этот стиль. Вместо этого он будет искать стиль, TargetType / Key которого имеет значение typeof (MyTextBox). Один из способов обойти это - установить для свойства Style значение DynamicResource для базового типа. например

public MyTextBox()
{
  this.SetResourceReference(StyleProperty, typeof(TextBox));
}

В основном это устанавливает локальное значение для свойства Style элемента управления, которое выполняет динамический поиск ресурсов для Style, чей Key (и, следовательно, TargetType для стилей, где x: Key не установлен) является указанным типом (в данном случае TextBox).

Как вы отметили, альтернативой является определение файлов xaml локально в вашей сборке для каждой темы, определяемой сборкой базового класса, а затем добавление ResourceDictionary в его MergedDictionaries, в котором используется нотация uri пакета для ссылки на ресурсы в сборке базового класса. Если вы устанавливаете DefaultStyleKey, вам, вероятно, потребуется определить Style, TargetType которого является типом вашего класса, в каждом из этих ResourceDictionaries, а затем установить в поле BasedOn значение StaticResource, где ключ ресурса является типом базового класса. Похоже, вам не нужно этого делать.

5
AndrewS 19 Апр 2013 в 18:25
'ExternalAssembly - это означает, что вы определяете отдельную сборку для ресурсов.' Против 'Вы не можете использовать ThemeInfo, чтобы сообщить WPF, что он должен искать ваши ресурсы в некоторой произвольной сборке.' Я беру "MyCustomControls.dll" и поместите внутри Theme / generic.xaml. Я сообщаю атрибутам ThemeInfo моего «MyCustomControl.dll», что темы определены во внешней сборке. Затем я беру свой «MyAnotherCustomControl.dll» и называю его в соответствии с соглашением об именах, чтобы «MyCustomControl.dll» нашел его. В конце Я использую ключ ресурса из MyAnotherControls.dll в MyCustomControls.dll. Будет ли это работать?
 – 
snowy hedgehog
19 Апр 2013 в 18:58
Я не знаю. Я никогда не пробовал этого, но вам должно быть достаточно легко попробовать. Я могу сказать, что если MyAnotherCustomControl подписан строгим именем, он определенно не будет работать, если ваша основная сборка не будет подписана тем же файлом открытого / закрытого ключа. Если вы хотите увидеть, как WPF выполняет разрешение, вы можете использовать Reflector / ILSpy и посмотреть на класс SystemResources.ResourceDictionaries, в частности на метод LoadExternalAssembly.
 – 
AndrewS
19 Апр 2013 в 19:51
У вас установлен DefaultStyleKey (или переопределены метаданные для) в производном классе? Вы пробовали его удалить? Каковы реальные проявления проблемы? Как я уже упоминал в своем ответе, независимо от того, что вы делаете, локальный неявный стиль всегда будет вашим типом управления по умолчанию, и единственный способ, который я знаю, - это упомянутый мною взлом.
 – 
AndrewS
19 Апр 2013 в 19:53