子类化 silverlight 模板化控件
Subclass a silverlight templated control
我想创建几个自定义控件。这是我要实现的目标的屏幕截图。
每个控件包含两部分,一个标签(TextBlock)和一个编辑器(UIElement)。标签部分对所有控件都是通用的。我不想在我创建的每个自定义控件中继续定义标签。所以我想到了创建一个基地class。这是基础编辑器 class。
[TemplatePart(Name = PartLabelName, Type = typeof (TextBlock))]
[TemplatePart(Name = PartEditorName, Type = typeof (ContentPresenter))]
public abstract class Editor : Control
{
protected const string PartLabelName = "PartLabel";
protected const string PartEditorName = "PartEditor";
public static readonly DependencyProperty LabelStyleProperty = DependencyProperty.Register(
"LabelStyle", typeof (Style), typeof (Editor), new PropertyMetadata(default(Style)));
public static readonly DependencyProperty LabelHeightProperty = DependencyProperty.Register(
"LabelHeight", typeof (double), typeof (Editor), new PropertyMetadata(default(double)));
public static readonly DependencyProperty LabelWidthProperty = DependencyProperty.Register(
"LabelWidth", typeof (double), typeof (Editor), new PropertyMetadata(default(double)));
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
"Label", typeof (string), typeof (Editor), new PropertyMetadata(default(string)));
public static readonly DependencyProperty EditorControlProperty = DependencyProperty.Register(
"EditorControl", typeof (FrameworkElement), typeof (Editor), new PropertyMetadata(default(FrameworkElement)));
public static readonly DependencyProperty EditorWidthProperty = DependencyProperty.Register(
"EditorWidth", typeof (double), typeof (Editor), new PropertyMetadata(default(double)));
public static readonly DependencyProperty EditorHeightProperty = DependencyProperty.Register(
"EditorHeight", typeof (double), typeof (Editor), new PropertyMetadata(default(double)));
public static readonly DependencyProperty EditorStyleProperty = DependencyProperty.Register(
"EditorStyle", typeof (Style), typeof (Editor), new PropertyMetadata(default(Style)));
public static readonly DependencyProperty LabelColorProperty = DependencyProperty.Register(
"LabelColor", typeof (Brush), typeof (Editor), new PropertyMetadata(default(Brush)));
private ContentPresenter _partEditorControl;
private TextBlock _partLabel;
protected Editor()
{
DefaultStyleKey = typeof (Editor);
}
public Brush LabelColor
{
get { return (Brush) GetValue(LabelColorProperty); }
set { SetValue(LabelColorProperty, value); }
}
public Style EditorStyle
{
get { return (Style) GetValue(EditorStyleProperty); }
set { SetValue(EditorStyleProperty, value); }
}
public double EditorHeight
{
get { return (double) GetValue(EditorHeightProperty); }
set { SetValue(EditorHeightProperty, value); }
}
public double EditorWidth
{
get { return (double) GetValue(EditorWidthProperty); }
set { SetValue(EditorWidthProperty, value); }
}
public Style LabelStyle
{
get { return (Style) GetValue(LabelStyleProperty); }
set { SetValue(LabelStyleProperty, value); }
}
public double LabelHeight
{
get { return (double) GetValue(LabelHeightProperty); }
set { SetValue(LabelHeightProperty, value); }
}
public double LabelWidth
{
get { return (double) GetValue(LabelWidthProperty); }
set { SetValue(LabelWidthProperty, value); }
}
public FrameworkElement EditorControl
{
get { return (FrameworkElement) GetValue(EditorControlProperty); }
set { SetValue(EditorControlProperty, value); }
}
public string Label
{
get { return (string) GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_partLabel = GetTemplateChild(PartLabelName) as TextBlock;
_partEditorControl = GetTemplateChild(PartEditorName) as ContentPresenter;
if (_partLabel == null || _partEditorControl == null)
{
throw new NullReferenceException("Template parts are not available");
}
}
这里是基本编辑器的样式。
<Style TargetType="local:Editor">
<Setter Property="LabelWidth" Value="200" />
<Setter Property="LabelHeight" Value="25" />
<Setter Property="EditorHeight" Value="25" />
<Setter Property="EditorWidth" Value="200" />
<Setter Property="LabelColor" Value="Black" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Editor">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="PartLabel"
Text="{TemplateBinding Label}"
Width="{TemplateBinding LabelWidth}"
Height="{TemplateBinding LabelHeight}"
Style="{TemplateBinding LabelStyle}"
Foreground="{TemplateBinding LabelColor}"
VerticalAlignment="Center" />
<ContentPresenter Grid.Column="1"
x:Name="PartEditor"
Height="{TemplateBinding EditorHeight}"
Width="{TemplateBinding EditorWidth}"
Style="{TemplateBinding EditorStyle}"
Content="{TemplateBinding EditorControl}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
所以我创建了我的第一个扩展编辑器的自定义控件 class。
[TemplatePart(Name = PartLabelName, Type = typeof (TextBlock))]
[TemplatePart(Name = PartEditorName, Type = typeof (ContentPresenter))]
public class NumericUpDownEditor : Editor
{
private ContentPresenter _partEditorControl;
private TextBlock _partLabel;
public NumericUpDownEditor()
{
DefaultStyleKey = typeof (NumericUpDownEditor);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_partLabel = GetTemplateChild(PartLabelName) as TextBlock;
_partEditorControl = GetTemplateChild(PartEditorName) as ContentPresenter;
if (_partLabel == null || _partEditorControl == null)
{
throw new NullReferenceException("Template parts are not available");
}
}
}
和默认样式
<Style TargetType="local:NumericUpDownEditor">
<Setter Property="EditorControl">
<Setter.Value>
<toolkit:NumericUpDown />
</Setter.Value>
</Setter>
</Style>
当我在用户控件中使用此 NumericEditor 时,没有任何显示。
<StackPanel x:Name="LayoutRoot" Orientation="Vertical">
<customControls:NumericUpDownEditor Label="Numeric Up" />
</StackPanel>
我只想在我创建的每个自定义控件中设置编辑器 UIElement。
我是否也需要在样式中为 NumericEditor 定义模板?或者我还做错了什么?
谢谢
发现错误。我想从 sub-classed 控件中删除默认样式。通过这个 answer 发现我要在 ContentTemplate (DataTemplate)
而不是 Content
中以 subclass 的样式声明编辑器部分控件
修改了编辑器样式和 class 代码
public static readonly DependencyProperty EditorControlTemplateProperty = DependencyProperty.Register(
"EditorControlTemplate", typeof (DataTemplate), typeof (Editor), new PropertyMetadata(default(DataTemplate)));
<ContentPresenter Grid.Column="1" x:Name="PartEditor"
Height="{TemplateBinding EditorHeight}"
Width="{TemplateBinding EditorWidth}"
Style="{TemplateBinding EditorStyle}"
Content="{TemplateBinding EditorControl}"
ContentTemplate="{TemplateBinding EditorControlTemplate}" />
修改子class编辑器
[TemplatePart(Name = PartLabelName, Type = typeof (TextBlock))]
[TemplatePart(Name = PartEditorName, Type = typeof (ContentPresenter))]
public class NumericUpDownEditor : Editor
{
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof (double), typeof (NumericUpDownEditor), new PropertyMetadata(default(double)));
private ContentPresenter _partEditorControl;
private TextBlock _partLabel;
public double Value
{
get { return (double) GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_partLabel = GetTemplateChild(PartLabelName) as TextBlock;
_partEditorControl = GetTemplateChild(PartEditorName) as ContentPresenter;
if (_partLabel == null || _partEditorControl == null)
{
throw new NullReferenceException("Template parts are not available");
}
}
}
下面是子classed 控件的样式
<Style TargetType="local:NumericUpDownEditor">
<Setter Property="EditorControlTemplate">
<Setter.Value>
<DataTemplate>
<toolkit:NumericUpDown
Value="{Binding RelativeSource={RelativeSource AncestorType=local:NumericUpDownEditor}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
我想创建几个自定义控件。这是我要实现的目标的屏幕截图。
每个控件包含两部分,一个标签(TextBlock)和一个编辑器(UIElement)。标签部分对所有控件都是通用的。我不想在我创建的每个自定义控件中继续定义标签。所以我想到了创建一个基地class。这是基础编辑器 class。
[TemplatePart(Name = PartLabelName, Type = typeof (TextBlock))]
[TemplatePart(Name = PartEditorName, Type = typeof (ContentPresenter))]
public abstract class Editor : Control
{
protected const string PartLabelName = "PartLabel";
protected const string PartEditorName = "PartEditor";
public static readonly DependencyProperty LabelStyleProperty = DependencyProperty.Register(
"LabelStyle", typeof (Style), typeof (Editor), new PropertyMetadata(default(Style)));
public static readonly DependencyProperty LabelHeightProperty = DependencyProperty.Register(
"LabelHeight", typeof (double), typeof (Editor), new PropertyMetadata(default(double)));
public static readonly DependencyProperty LabelWidthProperty = DependencyProperty.Register(
"LabelWidth", typeof (double), typeof (Editor), new PropertyMetadata(default(double)));
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(
"Label", typeof (string), typeof (Editor), new PropertyMetadata(default(string)));
public static readonly DependencyProperty EditorControlProperty = DependencyProperty.Register(
"EditorControl", typeof (FrameworkElement), typeof (Editor), new PropertyMetadata(default(FrameworkElement)));
public static readonly DependencyProperty EditorWidthProperty = DependencyProperty.Register(
"EditorWidth", typeof (double), typeof (Editor), new PropertyMetadata(default(double)));
public static readonly DependencyProperty EditorHeightProperty = DependencyProperty.Register(
"EditorHeight", typeof (double), typeof (Editor), new PropertyMetadata(default(double)));
public static readonly DependencyProperty EditorStyleProperty = DependencyProperty.Register(
"EditorStyle", typeof (Style), typeof (Editor), new PropertyMetadata(default(Style)));
public static readonly DependencyProperty LabelColorProperty = DependencyProperty.Register(
"LabelColor", typeof (Brush), typeof (Editor), new PropertyMetadata(default(Brush)));
private ContentPresenter _partEditorControl;
private TextBlock _partLabel;
protected Editor()
{
DefaultStyleKey = typeof (Editor);
}
public Brush LabelColor
{
get { return (Brush) GetValue(LabelColorProperty); }
set { SetValue(LabelColorProperty, value); }
}
public Style EditorStyle
{
get { return (Style) GetValue(EditorStyleProperty); }
set { SetValue(EditorStyleProperty, value); }
}
public double EditorHeight
{
get { return (double) GetValue(EditorHeightProperty); }
set { SetValue(EditorHeightProperty, value); }
}
public double EditorWidth
{
get { return (double) GetValue(EditorWidthProperty); }
set { SetValue(EditorWidthProperty, value); }
}
public Style LabelStyle
{
get { return (Style) GetValue(LabelStyleProperty); }
set { SetValue(LabelStyleProperty, value); }
}
public double LabelHeight
{
get { return (double) GetValue(LabelHeightProperty); }
set { SetValue(LabelHeightProperty, value); }
}
public double LabelWidth
{
get { return (double) GetValue(LabelWidthProperty); }
set { SetValue(LabelWidthProperty, value); }
}
public FrameworkElement EditorControl
{
get { return (FrameworkElement) GetValue(EditorControlProperty); }
set { SetValue(EditorControlProperty, value); }
}
public string Label
{
get { return (string) GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_partLabel = GetTemplateChild(PartLabelName) as TextBlock;
_partEditorControl = GetTemplateChild(PartEditorName) as ContentPresenter;
if (_partLabel == null || _partEditorControl == null)
{
throw new NullReferenceException("Template parts are not available");
}
}
这里是基本编辑器的样式。
<Style TargetType="local:Editor">
<Setter Property="LabelWidth" Value="200" />
<Setter Property="LabelHeight" Value="25" />
<Setter Property="EditorHeight" Value="25" />
<Setter Property="EditorWidth" Value="200" />
<Setter Property="LabelColor" Value="Black" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Editor">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="PartLabel"
Text="{TemplateBinding Label}"
Width="{TemplateBinding LabelWidth}"
Height="{TemplateBinding LabelHeight}"
Style="{TemplateBinding LabelStyle}"
Foreground="{TemplateBinding LabelColor}"
VerticalAlignment="Center" />
<ContentPresenter Grid.Column="1"
x:Name="PartEditor"
Height="{TemplateBinding EditorHeight}"
Width="{TemplateBinding EditorWidth}"
Style="{TemplateBinding EditorStyle}"
Content="{TemplateBinding EditorControl}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
所以我创建了我的第一个扩展编辑器的自定义控件 class。
[TemplatePart(Name = PartLabelName, Type = typeof (TextBlock))]
[TemplatePart(Name = PartEditorName, Type = typeof (ContentPresenter))]
public class NumericUpDownEditor : Editor
{
private ContentPresenter _partEditorControl;
private TextBlock _partLabel;
public NumericUpDownEditor()
{
DefaultStyleKey = typeof (NumericUpDownEditor);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_partLabel = GetTemplateChild(PartLabelName) as TextBlock;
_partEditorControl = GetTemplateChild(PartEditorName) as ContentPresenter;
if (_partLabel == null || _partEditorControl == null)
{
throw new NullReferenceException("Template parts are not available");
}
}
}
和默认样式
<Style TargetType="local:NumericUpDownEditor">
<Setter Property="EditorControl">
<Setter.Value>
<toolkit:NumericUpDown />
</Setter.Value>
</Setter>
</Style>
当我在用户控件中使用此 NumericEditor 时,没有任何显示。
<StackPanel x:Name="LayoutRoot" Orientation="Vertical">
<customControls:NumericUpDownEditor Label="Numeric Up" />
</StackPanel>
我只想在我创建的每个自定义控件中设置编辑器 UIElement。 我是否也需要在样式中为 NumericEditor 定义模板?或者我还做错了什么?
谢谢
发现错误。我想从 sub-classed 控件中删除默认样式。通过这个 answer 发现我要在 ContentTemplate (DataTemplate)
而不是 Content
修改了编辑器样式和 class 代码
public static readonly DependencyProperty EditorControlTemplateProperty = DependencyProperty.Register(
"EditorControlTemplate", typeof (DataTemplate), typeof (Editor), new PropertyMetadata(default(DataTemplate)));
<ContentPresenter Grid.Column="1" x:Name="PartEditor"
Height="{TemplateBinding EditorHeight}"
Width="{TemplateBinding EditorWidth}"
Style="{TemplateBinding EditorStyle}"
Content="{TemplateBinding EditorControl}"
ContentTemplate="{TemplateBinding EditorControlTemplate}" />
修改子class编辑器
[TemplatePart(Name = PartLabelName, Type = typeof (TextBlock))]
[TemplatePart(Name = PartEditorName, Type = typeof (ContentPresenter))]
public class NumericUpDownEditor : Editor
{
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof (double), typeof (NumericUpDownEditor), new PropertyMetadata(default(double)));
private ContentPresenter _partEditorControl;
private TextBlock _partLabel;
public double Value
{
get { return (double) GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_partLabel = GetTemplateChild(PartLabelName) as TextBlock;
_partEditorControl = GetTemplateChild(PartEditorName) as ContentPresenter;
if (_partLabel == null || _partEditorControl == null)
{
throw new NullReferenceException("Template parts are not available");
}
}
}
下面是子classed 控件的样式
<Style TargetType="local:NumericUpDownEditor">
<Setter Property="EditorControlTemplate">
<Setter.Value>
<DataTemplate>
<toolkit:NumericUpDown
Value="{Binding RelativeSource={RelativeSource AncestorType=local:NumericUpDownEditor}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>