стилизация общих элементов управления WPF - PullRequest
3 голосов
/ 19 декабря 2009

Я занимаюсь созданием безопасных для типов универсальных элементов управления. Он нацелен на поддержку (уменьшенная) универсальных шаблонов в WPF 4 и будущем Silverlight и будет включать иерархию общих элементов управления.

У меня два вопроса:

  1. Можно ли использовать установщики стилей и привязки шаблонов для неуниверсальных свойств, определенных в универсальном элементе управления?
  2. В Silverlight есть ли значение, которое я могу использовать для ключа стиля по умолчанию в базовом классе, который позволит использовать тот же стиль в (временных) производных классах определенного типа? (ComponentResourceKey не существует в Silverlight, поэтому описанная ниже настройка не работает.)

Тестовый общий элемент управления ниже определяет два тестовых свойства: неуниверсальное свойство Description и универсальное свойство Data. Управление устанавливает DefaultStyleKey на ComponentResourceKey для управления.

Вот как определяется контрольный контроль:

public class GenericControl<T> : Control {
  static GenericControl( ) {
    DefaultStyleKeyProperty.OverrideMetadata(
      typeof(GenericControl<T>), new FrameworkPropertyMetadata(
        new ComponentResourceKey( typeof(Proxy), "GenericControl`1" )
      )
    );
  }

  public static readonly DependencyProperty DescriptionProperty =
    DependencyProperty.Register(
      "Description", typeof(string), typeof(GenericControl<T>),
      new PropertyMetadata( "Default Description" )
    );
  public static readonly DependencyProperty DataProperty =
    DependencyProperty.Register(
      "Data", typeof(T), typeof(GenericControl<T>),
      new PropertyMetadata( default(T) )
    );

  public string Description { get { ... } set { ... } }
  public T Data { get { ... } set { ... } }
}

Вот стиль для контрольного контроля в generic.xaml:

<Style x:Key="{ComponentResourceKey {x:Type local:Proxy}, GenericControl`1}">
  <Setter Property="Control.Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Control}">
        <Border Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}"">
          <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Description, 
                             RelativeSource={RelativeSource TemplatedParent}}" />
            <TextBlock Text="{Binding Data,
                             RelativeSource={RelativeSource TemplatedParent}}" />
          </StackPanel>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Вот несколько примеров того, как этот тестовый элемент управления будет объявлен в xaml:

<ListBox Name="list" ... />
<GenericControl x:TypeArguments="sys:Int32" Description="Count: "
               Data="{Binding Items.Count, ElementName=list}" />

<Slider Name="slider" ... />
<GenericControl x:TypeArguments="sys:Double" Description="Slider Value: "
               Data="{Binding Value, ElementName=slider}" />

С текущей поддержкой универсальных шаблонов в WPF 4 вы не можете использовать открытый универсальный тип в качестве TargetType шаблона стиля или элемента управления (в результате получается, что TargetType GenericControl & # x60; 1 не соответствует типу исключение элемента 'GenericControl & # x60; 1'. "). Это имеет два основных последствия, как указано в вопросе 1 выше:

  • Вы должны использовать обычную привязку с RelativeSource={RelativeSource TemplatedParent} вместо TemplateBinding в шаблоне элемента управления для ссылки на свойства, определенные общим элементом управления.
  • Нельзя создать установщик стиля для свойства Description, даже если он не зависит от универсального типа элемента управления.

Для последнего есть обходной путь в WPF: просто определите неуниверсальные свойства как присоединенные свойства зависимостей для типа прокси. Затем вы можете использовать AddOwner, чтобы «объявить» свойства общего элемента управления, и вы можете использовать синтаксис «ProxyType.Property» в установщике стилей. Конечно, Silverlight не поддерживает AddOwner, и превращение того, что должно быть свойством экземпляра, в присоединенное свойство, в любом случае не является идеальным, поэтому это не является долгосрочным решением.

В сторону: Похоже, что существует регрессия в поведении синтаксического анализа xaml для типов. Используя VS2008, я могу использовать {x:Type local:GenericControl&#x60;1}, чтобы получить открытый тип элемента управления, который я использовал в качестве примера в ComponentResourceKey. Однако в VS2010 это приводит к следующей ошибке: "Символ '& # x60;' было неожиданным в строке 'local: GenericControl & # x60; 1'. Неверное имя типа XAML. ", поэтому я изменил его, чтобы использовать вместо него тип прокси.

Ответы [ 2 ]

2 голосов
/ 12 апреля 2010

Я отправил этот же вопрос на форумы WPF и Silverlight . Ответ на Silverlight не был получен, но вот краткое изложение ответа для WPF:

  • Цитируя Shreedhar , "XAML в настоящее время не поддерживает определение открытых универсальных типов".
  • Использование закрытого универсального типа, такого как TargetType="{x:Type local:GenericControl(x:Int32)}", будет работать для отдельного стиля, но потребует копирования и вставки для того же элемента управления для других параметров типа.
  • Может создать шаблон по умолчанию на лету для любого заданного аргумента типа, используя XamlReader и некоторую замену строки, но это оставляет желать лучшего при создании нового стиля или шаблона вне элемента управления.
1 голос
/ 19 декабря 2009
  1. Да, вы можете. Но ваш xaml должен быть основан только на неуниверсальном типе. Например, мы сделали управление ползунком вот так ...
SliderInt32 -> BaseRange<T> -> BaseSliderControl

Мы могли бы определять стиль только на BaseSliderControl или только SliderInt32, но не на BaseRange. Мы можем указать как общие, так и не общие свойства в классе BaseRange, и они хорошо работают в SliderInt32.

  1. Даже в Silverlight вы можете ввести родительский класс универсального класса, который может служить вашим ключом типа, как показано в примере выше. Стиль элемента управления «BaseSliderControl» всегда работает, пока дочерний элемент не переопределяет его.

Имя GenericControl`1 и т. Д. Не является правильным полностью определенным именем, поэтому оно никогда не будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...