WPF 自定义 ItemsControl 控件
该控件叫Summary, 主要是一些汇总信息的显示,有几个地方用,之前都是分散到各个XAML 文件里,不统一。
本人WPF新手,对XAML了解不多,做这个软件基本上都是用CM,界面布局用AvalonDock。由于缺乏相关经验,又没有一个能问得上的人指导,写这个控件费了我很长时间(啥时有空啥时动动)。
之前主要做一些功能方面的,没有心思美化界面,现在虽然还有很多功能没写,但是基本上够自己用了,放下心思来做一些界面上的东西,要不然何苦选择WPF?
先看一下图:
该CustomControl 由4部分组成:
大标题,小标题,值及Detail。
虽然细分这么多,但实质上还是一个列表类的控件,所以选择继承自ItemsControl.
做这个控件的时候,遇到了一些详细的问题不知道怎么解决,Google/Bing 都没有找到我要了解的,Baidu 更不用提了,漫天的转载,Copy.
1, 类似ComboBox 的DisplayMemberPath 如何弄?
既然都自定控件了,当然是想让它适用不同场景,不能局限于某一个实体类,最好是能像DisplayMemberPath https://www.360docs.net/doc/292205005.html, ValueMemberPath 这样的属性。
这里,我定义了:
ItemTitlePathProperty 及ItemValuePathProperty 来处理。
2,有了上面两个依赖属性,但是还不足以处理更多的场景,最好是能有不同的Template 。这里我定义了:
TitleTemplate / ValueTemplate及DetailTemplate.
第一个问题,只需定义一个简单的DataTemplate ,然后用TemplateBinding 即可做到。但是要和第二个问题结合在一起,就牵扯到模板切换及数据切换的问题,因为第一问题所用的数据被指定为某实体类的某个属性,第二个问题的数据要指定为整个实体。
解决第一个问题,需要重写PrepareContainerForItemOverride 方法,第二个需要重写OnApplyTemplate
不多说了,怕误导大家,毕竟,我懂的不多,上代码,供参考:
模板文件:
1 xmlns="https://www.360docs.net/doc/292205005.html,/winfx/2006/xaml/presentation" 2 xmlns:x="https://www.360docs.net/doc/292205005.html,/winfx/2006/xaml" 3 xmlns:local="clr-namespace:AsNum.WPF.Controls" 4> 5 6 7 8 9 10 11 12 13 Foreground="White"/> 14 15 16 17 18 19 20 21 23BorderBrush="{TemplateBinding BorderBrush}" 24BorderThickness="{TemplateBinding BorderThickness}" 25> 26 27 28 CornerRadius="5,5,0,0" Background="#10a8ab"> 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47Padding="3" 48BorderBrush="{TemplateBinding BorderBrush}" 49BorderThickness="{TemplateBinding BorderThickness}"> 50 51 52 53 54 55 56 57 58 Content="{TemplateBinding Title}" 60 ContentTemplate="{StaticResource SummaryTitleTemplate}" 61/> 62 63 x:Name="PART_Value" 64 Content="{TemplateBinding Value}" 65 ContentTemplate="{StaticResource SummaryValueTemplate}" 66Width="auto" 67 DockPanel.Dock="Right" 68 HorizontalAlignment="Right" 69/> 70 71 72 x:Name="PART_Detail" ContentTemplate="{TemplateBinding DetailTemplate}"/> 73 74 75 76 RoutedEvent="Border.MouseEnter"> 77 78 79 To="#FF535C7B" Duration="0:0:1" 80 Storyboard.TargetName="Item" 81 Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/> 82 83 84 85 RoutedEvent="Border.MouseLeave"> 86 87 88 To="Transparent" Duration="0:0:1" 89 Storyboard.TargetName="Item" 90 Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"/> 91 92 93 94 95 96 97 98 99 100 101 102 103
Summary.cs
1using System;
2using System.Collections.Generic;
3using System.Collections.ObjectModel;
4using System.Linq;
5using System.Text;
6using System.Threading.Tasks;
7using System.Windows;
8using System.Windows.Controls;
9using System.Windows.Data;
10using System.Windows.Documents;
11using System.Windows.Input;
12using System.Windows.Media;
13using System.Windows.Media.Imaging;
14using System.Windows.Navigation;
15using System.Windows.Shapes;
16
17namespace AsNum.WPF.Controls {
18public class Summary : ItemsControl {
19
20
21public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(Summary));
22
23public static DependencyProperty ItemTitlePathProperty = DependencyProperty.Register("ItemTitlePath", typeof(string), typeof(Summary)); 24
25public static DependencyProperty ItemValuePathProperty = DependencyProperty.Register("ItemValuePath", typeof(string), typeof(Summary)); 26
27public static DependencyProperty ItemDetailTemplateProperty = DependencyProperty.Register("ItemDetailTemplate", typeof(DataTemplate), typeof(Summary));
28
29public static DependencyProperty ItemTitleTemplateProperty = DependencyProperty.Register("ItemTitleTemplate", typeof(DataTemplate), typeof(Summary));
30
31public static DependencyProperty ItemValueTemplateProperty = DependencyProperty.Register("ItemValueTemplate", typeof(DataTemplate), typeof(Summary));
32
33public string Title {
34get {
35return (string)this.GetValue(TitleProperty);
36}
37set {
38this.SetValue(TitleProperty, value);
39}
40}
41
42public string ItemTitlePath {
43get {
44return (string)this.GetValue(ItemTitlePathProperty); 45}
46set {
47this.SetValue(ItemTitlePathProperty, value);
48}
49}
50
51public string ItemValuePath {
52get {
53return (string)this.GetValue(ItemValuePathProperty); 54}
55set {
56this.SetValue(ItemValuePathProperty, value);
57}
58}
59
60public DataTemplate ItemDetailTemplate {
61get {
62return
(DataTemplate)this.GetValue(ItemDetailTemplateProperty);
63}
64set {
65this.SetValue(ItemDetailTemplateProperty, value);
66}
67}
68
69public DataTemplate ItemTitleTemplate {
70get {
71return
(DataTemplate)this.GetValue(ItemTitleTemplateProperty);
72}
73set {
74this.SetValue(ItemTitleTemplateProperty, value);
75}
76}
77
78public DataTemplate ItemValueTemplate {
79get {
80return
(DataTemplate)this.GetValue(ItemValueTemplateProperty);
81}
82set {
83this.SetValue(ItemValueTemplateProperty, value);
84}
85}
86
87static Summary() {
88DefaultStyleKeyProperty.OverrideMetadata(typeof(Summary), new FrameworkPropertyMetadata(typeof(Summary)));
89}
90
91protected override void
PrepareContainerForItemOverride(DependencyObject element, object item) {
92base.PrepareContainerForItemOverride(element, item);
93var ele = element as SummaryItem;
94
95{
96Binding binding = new Binding();
97ele.SetBinding(SummaryItem.ItemProperty, binding);
98}
99
100if (!string.IsNullOrEmpty(this.ItemTitlePath)) {
101Binding binding = new Binding(this.ItemTitlePath);
102ele.SetBinding(SummaryItem.TitleProperty, binding); 103}
104
105if (!string.IsNullOrEmpty(this.ItemValuePath)) {
106Binding binding = new Binding(this.ItemValuePath);
107ele.SetBinding(SummaryItem.ValueProperty, binding); 108}
109
110ele.DetailTemplate = this.ItemDetailTemplate;
111ele.TitleTemplate = this.ItemTitleTemplate;
112ele.ValueTemplate = this.ItemValueTemplate;
113}
114
115protected override DependencyObject GetContainerForItemOverride() {
116return new SummaryItem();
117}
118
119}
120 }
SummaryItem.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Threading.Tasks;
6using System.Windows;
7using System.Windows.Controls;
8using System.Windows.Data;
9using System.Windows.Documents;
10using System.Windows.Input;
11using System.Windows.Media;
12using System.Windows.Media.Imaging;
13using System.Windows.Navigation;
14using System.Windows.Shapes;
15
16namespace AsNum.WPF.Controls {
17
18[TemplatePart(Name = "PART_Value", Type=typeof(ContentControl))] 19[TemplatePart(Name = "PART_Title", Type = typeof(ContentControl))] 20[TemplatePart(Name = "PART_Detail", Type = typeof(ContentControl))] 21public class SummaryItem : Control {
22
23public static DependencyProperty ItemProperty = DependencyProperty.Register("Item", typeof(object), typeof(Summary));
24public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(SummaryItem));
25public static DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(SummaryItem));
26public static DependencyProperty DetailTemplateProperty = DependencyProperty.Register("DetailTemplate", typeof(DataTemplate),
typeof(SummaryItem));
27public static DependencyProperty TitleTemplateProperty = DependencyProperty.Register("TitleTemplate", typeof(DataTemplate),
typeof(SummaryItem));
28public static DependencyProperty ValueTemplateProperty = DependencyProperty.Register("ValueTemplate", typeof(DataTemplate),
typeof(SummaryItem));
29
30public object Item {
31get {
32return (object)this.GetValue(ItemProperty);
33}
34set {
35this.SetValue(ItemProperty, value);
36}
37}
38public string Title {
39get {
40return (string)this.GetValue(TitleProperty);
41}
42set {
43this.SetValue(TitleProperty, value);
44}
45}
46
47public object Value {
48get {
49return this.GetValue(ValueProperty);
50}
51set {
52this.SetValue(ValueProperty, value);
53}
54}
55
56public DataTemplate DetailTemplate {
57get {
58return
(DataTemplate)this.GetValue(DetailTemplateProperty);
59}
60set {
61this.SetValue(DetailTemplateProperty, value);
62}
63}
64
65public DataTemplate TitleTemplate {
66get {
67return (DataTemplate)this.GetValue(TitleTemplateProperty); 68}
69set {
70this.SetValue(TitleTemplateProperty, value);
71}
72}
73
74public DataTemplate ValueTemplate {
75get {
76return
(DataTemplate)this.GetValue(ValueTemplateProperty);
77}
78set {
79this.SetValue(ValueTemplateProperty, value);
80}
81}
82
83static SummaryItem() {
84
DefaultStyleKeyProperty.OverrideMetadata(typeof(SummaryItem), new FrameworkPropertyMetadata(typeof(SummaryItem)));
85}
86
87public override void OnApplyTemplate() {
88base.OnApplyTemplate();
89
90var pv =
(ContentControl)this.Template.FindName("PART_Value", this);
91if (pv != null && this.ValueTemplate != null) {
92pv.Content = this.Item;
93pv.ContentTemplate = this.ValueTemplate;
94}
95
96var pt = (ContentControl)this.Template.FindName("PART_Title", this);
97if (pt != null && this.TitleTemplate != null) {
98pt.Content = this.Item;
99pt.ContentTemplate = this.TitleTemplate;
100}
101
102var pd =
(ContentControl)this.Template.FindName("PART_Detail", this);
103if (pd != null && this.DetailTemplate != null) {
104pd.Content = this.Item;
105}
106}
107}
108 }
用法:
1
2
3 4Title="{Binding Title2}" ItemsSource="{Binding Items2}" 5ItemTitlePath="Title2" ItemValuePath="Value"> 6 7 8 9 10 11 12 13 14 15 16 17
还有一些小细节需要自行调整。
wpf自定义slider控件
自定义Slider控件 最终效果: 界面: