I am studying the creation of universal type controls. This is aimed at (reduced) generic support in WPF 4 and future Silverlight and will contain a hierarchy of common controls.
I have two questions:
- Can you use style settings and template bindings for non-generic properties defined in a common control?
- In Silverlight, is there a value that I can use for the default style keyword in the base class, which allows me to use the same style in (temporary) classes of a certain type? (
ComponentResourceKeyDoes not exist in Silverlight, so the setting described below does not work.)
The control general control below defines two test properties: not a common property Descriptionand a common property Data. The control sets DefaultStyleKeyin ComponentResourceKeyto control.
Here's how test management is defined:
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 { ... } }
}
Here is the style for the control in 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>
Here are some examples of how this test control will be declared in 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}" />
With the current generics support in WPF 4, you cannot use an open generic type as the TargetTypeof a style or control template (doing so results in a "'GenericControl`1' TargetType does not match type of element 'GenericControl`1'." exception). This has two main consequences, as mentioned in question 1 above:
RelativeSource={RelativeSource TemplatedParent} TemplateBinding , .Description, .
WPF : . AddOwner, "" , "ProxyType.Property" . , Silverlight AddOwner, , , , .
Aside: It looks like there is a regression in the xaml parsing behavior for types. Using VS2008, can use {x:Type local:GenericControl`1} to get the open type of the control, which used as the example type in the ComponentResourceKey. In VS2010 though, this results in the following error: "Character '`' was unexpected in string 'local:GenericControl`1'. Invalid XAML type name.", so changed it to use the proxy type instead.