WPF可以创建两种控件,它们的名字也很容易让人混淆:用户控件(User Control)和定制控件(Customer Control),之所以如此命名,是因为用户控件更面向控件的“使用者”,以方面他们利用现成的控件组合成新的控件,而客户控件,更便于定制化(Customization),方便创建有别于现有控件的定制控件。
定制控件提供了行为和表现完全分离的开发模式,具有很高的灵活性,当然,也更难一些。这里我们通过创建个简单的搜索控件来看看如何开发定制控件:
首先我们创建一个WPF应用,在同一个solution里,再添加一个用户WPF控件库。
系统会自动在控件库里创建一个UserControl1.XAML,这个文件可以直接删除。在WPF控件库里添加一个新的项目,注意:应该选择定制控件而不是用户控件,如图:
现在程序结构看起来应该像这样子:
定制控件的模板会为我们建立FilterTextBox.cs和Generic.xaml文件。
前者内容如下:
public class FilterTextBox : Control{
static FilterTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FilterTextBox),
new FrameworkPropertyMetadata(typeof(FilterTextBox)));
}}
generic.xaml是定制控件的外观表现,默认在themes目录下
<Style TargetType="{x:Type local:FilterTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FilterTextBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding
BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
现在generic.xaml的border还是空的。
接下来,我们先为控件创建其行为。首先我们添加一个叫"Text"的依赖属性,这是用户输入的搜索文本。这儿我们创建了个Callback,这样属性改变时就会被调用。注意不要在CLR属性的getter和setter添加任何代码,因为在运行时,WPF会忽略这些属性而直接调用GetValue和SetValue.但是在xaml里使用属性时,你仍需要CLR属性。
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text",
typeof(String),
typeof(FilterTextBox),
new UIPropertyMetadata(null,
new PropertyChangedCallback(OnTextChanged),
new CoerceValueCallback(OnCoerceText)));
private static object OnCoerceText(DependencyObject o, Object value)
{
FilterTextBox filterTextBox = o as FilterTextBox;
if (filterTextBox != null)
return filterTextBox.OnCoerceText((String)value);
else
return value;
}
private static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
FilterTextBox filterTextBox = o as FilterTextBox;
if (filterTextBox != null)
filterTextBox.OnTextChanged((String)e.OldValue, (String)e.NewValue);
}
protected virtual String OnCoerceText(String value)
{
return value;
}
protected virtual void OnTextChanged(String oldValue, String newValue)
{
}
public String Text
{
// IMPORTANT: To maintain parity between setting a property in XAML
// and procedural code, do not touch the getter and setter inside
// this dependency property!
get
{
return (String)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
接着我们还要暴露出一些事件,这样当文本被修改时,控件的用户就会被通知到,这儿为控件添加一个"TextChangeEvent"。
public static readonly RoutedEvent TextChangedEvent = EventManager.RegisterRoutedEvent("TextChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FilterTextBox));
public event RoutedEventHandler TextChanged
{
add { AddHandler(TextChangedEvent, value); }
remove { RemoveHandler(TextChangedEvent, value); }
}
事件在OnTextChange方法里被触发:
protected virtual void OnTextChanged(String oldValue, String newValue)
{
this.RaiseEvent(new RoutedEventArgs(FilterTextBox.TextChangedEvent, this));
}
到这里,关于控件行为的代码已经基本完成了,我们继续前进,为我们的控件创建一个外观。我们添加一个DockPanel,并在其中加入一个文本框和一个按钮。按钮Dock在右边。然后我们把文本框的Text属性和我们控件的Text属性绑定起来。同时设置UpdateSourceTrigge为TextChanged,这样每次用户在文本框输入点什么东西,就会触发我们写的TextChanged事件。注意,文本框没有border,因为这儿不需要2个Border。
<ControlTemplate TargetType="{x:Type local:FilterTextBox}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="3">
<DockPanel
LastChildFill="True"
Margin="1">
<Button
x:Name="PART_ClearFilterButton"
Content="X"
Width="20"
ToolTip="Clear Filter"
DockPanel.Dock="Right" />
<TextBox
x:Name="PART_FilterTextBox"
Text="{Binding Path=Text,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,RelativeSource={RelativeSource TemplatedParent}}"
BorderBrush="{x:Null}"
BorderThickness="0"
VerticalAlignment="Center" />
</DockPanel>
</Border>
</ControlTemplate>
特别要注意的是这些控件的名称。他们都以"PART_"开头,这是WPF的标准方法用来表示那些需要被替换的控件,当我们要修改控件的模板的时候。如果有人为你的控件编写模板,你需要验证所用的部件的类型是控件所必需的。可以通过TemplatePart Attribute,并添加部件的名称和类型。
[TemplatePart(Name = "PART_FilterTextBox", Type = typeof(TextBox))]
[TemplatePart(Name = "PART_ClearFilterButton", Type = typeof(Button))]
public class FilterTextBox : Control{
...
}
我们还设想只有在文本框里有文本的时候,一个“清空”的按钮才显示出来。我们创建一个DataTriger来实现这个想法:
<ControlTemplate TargetType="{x:Type local:FilterTextBox}">
<Border>
...
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Text.Length, ElementName=PART_FilterTextBox}" Value="0">
<Setter TargetName="PART_ClearFilterButton" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
现在要处理的是当用户点击"清空"按钮时候的动作,可以通过重写OnApplyTemplate来实现。通过控件名调用GetTemplateChild可以得到控件的引用。当用户点击“清空”按钮时,我们想删除文本框里的所有文本。得到文本框的引用和上面的方法相同。
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Button clearFilterButton = base.GetTemplateChild("PART_ClearFilterButton") as Button;
if (clearFilterButton != null)
{
clearFilterButton.Click += new RoutedEventHandler(ClearFilterButton_Click);
}
}
private void ClearFilterButton_Click(Object sender, RoutedEventArgs e)
{
TextBox textBox = base.GetTemplateChild("PART_FilterTextBox") as TextBox;
if (textBox != null)
{
textBox.Text = String.Empty;
}
}
现在可以在WPF应用里跑一下了!
参考:
http://pavanpodila.spaces.live.com/blog/cns!9C9E888164859398!135.entry
- 大小: 17 KB
- 大小: 68.6 KB
- 大小: 17.4 KB
分享到:
相关推荐
WPF系统控件模板查看器,可以wpf控件样式文件,对学习wpf的样式很有帮助
使用UserControl创建WPF模板控件,通过该模板设计可变部分内容,模板为不可变内容。
wpf控件模板,标注控件模板工具,反编译微软windows各种风格
wpf控件标准模板,可选择后自动查看标准模板
可查看wpf控件模板的源xaml,方便重写控件样式。。。。。。。。。。。。。。。。。。。。。。。。。。
可用来查看WPF的控件模板组成,利于了解控件默认模板的组成部分。
可以查看.net自带的标准WPF控件模板.
wpf控件及模板列表源代码 列出所有wpf控件及标准模板,供学习wpf模板的同学参考学习
WPF控件样式模板查询手册
该工具可以查看WPF控件的默认模板,大家可以拷贝下来进行修改。以前误认为MSDN上的控件模板就是默认的模板,结果发现有的控件无法更改,用这个工具则很容易解决了问题,因为原始模板的所有信息都被展现出来了
该项目重写了WPF中的日期控件,选择当前日期,过去日期,可选日期,整体界面重新重写。另一个项目带有滚动时间,按像素点滚动。
可以查询常用的wpf控件的模板,学习和编程的好工具
用于查看wpf中系统控件的模板,可以通过模板修改适合自己使用的模板。
1. WPF控件开发之控件概述 95 2. 使用XAML创建按钮 103 3. WPF控件库之BUTTON 114 4. WPF控件库之MENU 115 5. WPF控件库之LABLE 119 6. WPF控件库之TOOLBAR 121 7. WPF控件开发之自定义控件 124 8. WPF控件开发之...
本软件用于展示WPF控件默认的模板,包括Template,ItemTemplate,方便学习WPF的同学了解微软官方是如何写控件的样式、模板的。
wpf控件模板可以很方便高效的改变控件的外观
微软WPF基础控件库模板,想知道Button,DataGrid和TextBlock等是怎样设计的?想在他们的基础上增加你的创意设计?那就的download吧
包含WPF大部分控件的详细描述(706页) 包括属性、事件、模板类型等。 控件库包含提供由 Windows Presentation Foundation (WPF),按字母顺 序列出的控件的信息。 内容模型概述了适用于 WPF 控件和类似控件的类型的...
WPF控件开发之控件概述2. 使用XAML创建按钮3. WPF控件库之BUTTON1164. WPF控件库之MENU1175. WPF控件库之LABLE 6. WPF控件库之TOOLBAR 7. WPF控件开发之自定义控件8. WPF控件开发之装饰器1. WPF 图形动画和媒体概述...
WPF_进阶视频教程(共113集)-001创建控件模板.mp4