WPF 自定义 ItemsControl 控件

WPF 自定义 ItemsControl 控件
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

41

42

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