原文:示例:WPF开发的简单ObjectProperyForm用来绑定实体表单

一、目的:自定义控件,用来直接绑定实体数据,简化开发周期

二、实现:

1、绑定实体对象

2、通过特性显示属性名称

3、通过特性增加验证条件

4、已经实现String、Int、Double、DateTime、Bool几种简单类型的DataTemplate模板,其他模板支持扩展

5、其他后续更新...

三、示例:

示例:WPF开发的简单ObjectProperyForm用来绑定实体表单-LMLPHP

实体定义如下:


  1. public class Student
  2. {
  3. [Display("姓名")]
  4. [Required]
  5. public string Name { get; set; }
  6. [Display("班级")]
  7. [Required]
  8. public string Class { get; set; }
  9. [Display("地址")]
  10. [Required]
  11. public string Address { get; set; }
  12. [Display("邮箱")]
  13. [Required]
  14. public string Emall { get; set; }
  15. [Display("可用")]
  16. [Required]
  17. public bool IsEnbled { get; set; }
  18. [Display("时间")]
  19. [Required]
  20. public DateTime time { get; set; }
  21. [Display("年龄")]
  22. [Required]
  23. public int Age { get; set; }
  24. [Display("平均分")]
  25. public double Score { get; set; }
  26. [Display("电话号码")]
  27. [Required]
  28. [RegularExpression(@"^1[3|4|5|7|8][0-9]{9}$", ErrorMessage = "手机号码不合法!")]
  29. public string Tel { get; set; }
  30. }

DisplayAttribute:用来标识显示名称

ResuiredAttribute:用来标识数据不能为空

RgularExpression:引用正则表达式验证数据是否匹配

其他特性后续更新...

应用方式:


  1. <UserControl.Resources>
  2. <local:Student x:Key="S.Student.HeBianGu"
  3. Name="河边骨"
  4. Address="四川省成都市高新区"
  5. Class="四年级"
  6. Emall="[email protected]" Age="33" Score="99.99" IsEnbled="True" time="2019-09-09"/>
  7. </UserControl.Resources>
  8. <wpfcontrollib:ObjectPropertyForm Grid.Row="1" Title="学生信息" SelectObject="{StaticResource S.Student.HeBianGu}" >
  9. <base:Interaction.Behaviors>
  10. <base:MouseDragElementBehavior ConstrainToParentBounds="True"/>
  11. <base:SelectZIndexElementBehavior/>
  12. </base:Interaction.Behaviors>

四、代码

1、通过反射获取属性和特性


  1. ObservableCollection<ObjectPropertyItem> PropertyItemSource
  2. {
  3. get { return (ObservableCollection<ObjectPropertyItem>)GetValue(PropertyItemSourceProperty); }
  4. set { SetValue(PropertyItemSourceProperty, value); }
  5. }
  6. // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
  7. public static readonly DependencyProperty PropertyItemSourceProperty =
  8. DependencyProperty.Register("PropertyItemSource", typeof(ObservableCollection<ObjectPropertyItem>), typeof(ObjectPropertyForm), new PropertyMetadata(new ObservableCollection<ObjectPropertyItem>(), (d, e) =>
  9. {
  10. ObjectPropertyForm control = d as ObjectPropertyForm;
  11. if (control == null) return;
  12. ObservableCollection<ObjectPropertyItem> config = e.NewValue as ObservableCollection<ObjectPropertyItem>;
  13. }));
  14. void RefreshObject(object o)
  15. {
  16. Type type = o.GetType();
  17. var propertys = type.GetProperties();
  18. this.PropertyItemSource.Clear();
  19. foreach (var item in propertys)
  20. {
  21. var from = ObjectPropertyFactory.Create(item, o);
  22. this.PropertyItemSource.Add(from);
  23. }
  24. this.ItemsSource = this.PropertyItemSource;
  25. }

2、定义类型基类、扩展之类和工厂方法


  1. /// <summary> 类型基类 </summary>
  2. public class ObjectPropertyItem : NotifyPropertyChanged
  3. {
  4. public string Name { get; set; }
  5. public PropertyInfo PropertyInfo { get; set; }
  6. public object Obj { get; set; }
  7. public ObjectPropertyItem(PropertyInfo property, object obj)
  8. {
  9. PropertyInfo = property;
  10. var display = property.GetCustomAttribute<DisplayAttribute>();
  11. Name = display == null ? property.Name : display.Name;
  12. Obj = obj;
  13. }
  14. }
  15. /// <summary> 泛型类型基类 </summary>
  16. public class ObjectPropertyItem<T> : ObjectPropertyItem
  17. {
  18. private T _value;
  19. /// <summary> 说明 </summary>
  20. public T Value
  21. {
  22. get { return _value; }
  23. set
  24. {
  25. this.Message = null;
  26. // Do:检验数据有效性
  27. if (Validations != null)
  28. {
  29. foreach (var item in Validations)
  30. {
  31. if (!item.IsValid(value))
  32. {
  33. this.Message = item.ErrorMessage;
  34. }
  35. }
  36. }
  37. _value = value;
  38. RaisePropertyChanged("Value");
  39. this.SetValue(value);
  40. }
  41. }
  42. void SetValue(T value)
  43. {
  44. this.PropertyInfo.SetValue(Obj, value);
  45. }
  46. List<ValidationAttribute> Validations { get; }
  47. public ObjectPropertyItem(PropertyInfo property, object obj) : base(property, obj)
  48. {
  49. Value = (T)property.GetValue(obj);
  50. Validations = property.GetCustomAttributes<ValidationAttribute>()?.ToList();
  51. if(Validations!=null&& Validations.Count>0)
  52. {
  53. this.Flag = "*";
  54. }
  55. }
  56. private string _message;
  57. /// <summary> 说明 </summary>
  58. public string Message
  59. {
  60. get { return _message; }
  61. set
  62. {
  63. _message = value;
  64. RaisePropertyChanged("Message");
  65. }
  66. }
  67. public string Flag { get; set; }
  68. }
  69. /// <summary> 字符串属性类型 </summary>
  70. public class StringPropertyItem : ObjectPropertyItem<string>
  71. {
  72. public StringPropertyItem(PropertyInfo property, object obj) : base(property, obj)
  73. {
  74. }
  75. }
  76. /// <summary> 时间属性类型 </summary>
  77. public class DateTimePropertyItem : ObjectPropertyItem<DateTime>
  78. {
  79. public DateTimePropertyItem(PropertyInfo property, object obj) : base(property, obj)
  80. {
  81. }
  82. }
  83. /// <summary> Double属性类型 </summary>
  84. public class DoublePropertyItem : ObjectPropertyItem<double>
  85. {
  86. public DoublePropertyItem(PropertyInfo property, object obj) : base(property, obj)
  87. {
  88. }
  89. }
  90. /// <summary> Int属性类型 </summary>
  91. public class IntPropertyItem : ObjectPropertyItem<int>
  92. {
  93. public IntPropertyItem(PropertyInfo property, object obj) : base(property, obj)
  94. {
  95. }
  96. }
  97. /// <summary> Bool属性类型 </summary>
  98. public class BoolPropertyItem : ObjectPropertyItem<bool>
  99. {
  100. public BoolPropertyItem(PropertyInfo property, object obj) : base(property, obj)
  101. {
  102. }
  103. }

类型工厂:


  1. public class ObjectPropertyFactory
  2. {
  3. public static ObjectPropertyItem Create(PropertyInfo info, object obj)
  4. {
  5. if (info.PropertyType == typeof(int))
  6. {
  7. return new IntPropertyItem(info, obj);
  8. }
  9. else if (info.PropertyType == typeof(string))
  10. {
  11. return new StringPropertyItem(info, obj);
  12. }
  13. else if (info.PropertyType == typeof(DateTime))
  14. {
  15. return new DateTimePropertyItem(info, obj);
  16. }
  17. else if (info.PropertyType == typeof(double))
  18. {
  19. return new DoublePropertyItem(info, obj);
  20. }
  21. else if (info.PropertyType == typeof(bool))
  22. {
  23. return new BoolPropertyItem(info, obj);
  24. }
  25. return null;
  26. }
  27. }

3、样式模板


  1. <DataTemplate DataType="{x:Type base:StringPropertyItem}">
  2. <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}"
  3. Height="35" Margin="5,0">
  4. <Grid.ColumnDefinitions>
  5. <ColumnDefinition Width="*"/>
  6. <ColumnDefinition Width="Auto"/>
  7. <ColumnDefinition Width="2*"/>
  8. <ColumnDefinition Width="30"/>
  9. </Grid.ColumnDefinitions>
  10. <TextBlock Text="{Binding Name}"
  11. FontSize="14"
  12. HorizontalAlignment="Center"
  13. VerticalAlignment="Center"/>
  14. <TextBlock Text="{Binding Flag}"
  15. Grid.Column="1" Margin="5,0"
  16. FontSize="14" Foreground="{DynamicResource S.Brush.Red.Notice}"
  17. HorizontalAlignment="Right"
  18. VerticalAlignment="Center"/>
  19. <local:FTextBox Text="{Binding Value,UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource DefaultTextBox}"
  20. FontSize="14" Width="Auto" CaretBrush="Black"
  21. Grid.Column="2" Height="30" base:ControlAttachProperty.FIcon=""
  22. VerticalContentAlignment="Center"
  23. HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
  24. <TextBlock Text="" Grid.Column="3" Style="{DynamicResource FIcon }"
  25. Foreground="{DynamicResource S.Brush.Red.Notice}"
  26. Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null},Mode=TwoWay}"
  27. FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"
  28. HorizontalAlignment="Center"
  29. VerticalAlignment="Center"/>
  30. </Grid>
  31. </DataTemplate>
  32. <DataTemplate DataType="{x:Type base:BoolPropertyItem}">
  33. <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}" Height="35" Margin="5,0">
  34. <Grid.ColumnDefinitions>
  35. <ColumnDefinition Width="*"/>
  36. <ColumnDefinition Width="Auto"/>
  37. <ColumnDefinition Width="2*"/>
  38. <ColumnDefinition Width="30"/>
  39. </Grid.ColumnDefinitions>
  40. <TextBlock Text="{Binding Name}"
  41. FontSize="14"
  42. HorizontalAlignment="Center"
  43. VerticalAlignment="Center"/>
  44. <TextBlock Text="{Binding Flag}"
  45. Grid.Column="1" Margin="5,0"
  46. FontSize="14" Foreground="{DynamicResource S.Brush.Red.Notice}"
  47. HorizontalAlignment="Right"
  48. VerticalAlignment="Center"/>
  49. <CheckBox IsChecked="{Binding Value}" FontSize="14" Grid.Column="2" Height="30"
  50. VerticalContentAlignment="Center"
  51. HorizontalAlignment="Left" VerticalAlignment="Center"/>
  52. <TextBlock Text="" Grid.Column="3" Style="{DynamicResource FIcon }"
  53. Foreground="{DynamicResource S.Brush.Red.Notice}" Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null}}"
  54. FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"
  55. HorizontalAlignment="Center"
  56. VerticalAlignment="Center"/>
  57. </Grid>
  58. </DataTemplate>
  59. <DataTemplate DataType="{x:Type base:DateTimePropertyItem}">
  60. <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}" Height="35" Margin="5,0">
  61. <Grid.ColumnDefinitions>
  62. <ColumnDefinition Width="*"/>
  63. <ColumnDefinition Width="Auto"/>
  64. <ColumnDefinition Width="2*"/>
  65. <ColumnDefinition Width="30"/>
  66. </Grid.ColumnDefinitions>
  67. <TextBlock Text="{Binding Name}"
  68. FontSize="14"
  69. HorizontalAlignment="Center"
  70. VerticalAlignment="Center"/>
  71. <TextBlock Text="{Binding Flag}"
  72. Grid.Column="1" Margin="5,0"
  73. FontSize="14" Foreground="{DynamicResource S.Brush.Red.Notice}"
  74. HorizontalAlignment="Right"
  75. VerticalAlignment="Center"/>
  76. <DatePicker SelectedDate="{Binding Value}" FontSize="14" Grid.Column="2" Height="30"
  77. VerticalContentAlignment="Center" Width="Auto"
  78. HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
  79. <TextBlock Text="" Grid.Column="3" Style="{DynamicResource FIcon }"
  80. Foreground="{DynamicResource S.Brush.Red.Notice}" Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null}}"
  81. FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"
  82. HorizontalAlignment="Center"
  83. VerticalAlignment="Center"/>
  84. </Grid>
  85. </DataTemplate>
  86. <DataTemplate DataType="{x:Type base:IntPropertyItem}">
  87. <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}" Height="35" Margin="5,0">
  88. <Grid.ColumnDefinitions>
  89. <ColumnDefinition Width="*"/>
  90. <ColumnDefinition Width="Auto"/>
  91. <ColumnDefinition Width="2*"/>
  92. <ColumnDefinition Width="30"/>
  93. </Grid.ColumnDefinitions>
  94. <TextBlock Text="{Binding Name}"
  95. FontSize="14"
  96. HorizontalAlignment="Center"
  97. VerticalAlignment="Center"/>
  98. <TextBlock Text="{Binding Flag}"
  99. Grid.Column="1" Margin="5,0"
  100. FontSize="14" Foreground="{DynamicResource S.Brush.Red.Notice}"
  101. HorizontalAlignment="Right"
  102. VerticalAlignment="Center"/>
  103. <Slider Value="{Binding Value}" FontSize="14" Grid.Column="2" Height="30"
  104. VerticalContentAlignment="Center"
  105. HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
  106. <TextBlock Text="" Grid.Column="3" Style="{DynamicResource FIcon }"
  107. Foreground="{DynamicResource S.Brush.Red.Notice}" Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null}}"
  108. FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"
  109. HorizontalAlignment="Center"
  110. VerticalAlignment="Center"/>
  111. </Grid>
  112. </DataTemplate>
  113. <DataTemplate DataType="{x:Type base:DoublePropertyItem}">
  114. <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}" Height="35" Margin="5,0">
  115. <Grid.ColumnDefinitions>
  116. <ColumnDefinition Width="*"/>
  117. <ColumnDefinition Width="Auto"/>
  118. <ColumnDefinition Width="2*"/>
  119. <ColumnDefinition Width="30"/>
  120. </Grid.ColumnDefinitions>
  121. <TextBlock Text="{Binding Name}"
  122. FontSize="14"
  123. HorizontalAlignment="Center"
  124. VerticalAlignment="Center"/>
  125. <TextBlock Text="{Binding Flag}"
  126. Grid.Column="1" Margin="5,0"
  127. FontSize="14" Foreground="{DynamicResource S.Brush.Red.Notice}"
  128. HorizontalAlignment="Right"
  129. VerticalAlignment="Center"/>
  130. <Slider Value="{Binding Value}" FontSize="14" Grid.Column="2" Height="30"
  131. VerticalContentAlignment="Center"
  132. HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
  133. <TextBlock Text="" Grid.Column="3" Style="{DynamicResource FIcon }"
  134. Foreground="{DynamicResource S.Brush.Red.Notice}" Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null}}"
  135. FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"
  136. HorizontalAlignment="Center"
  137. VerticalAlignment="Center"/>
  138. </Grid>
  139. </DataTemplate>
  140. <Style TargetType="local:ObjectPropertyForm">
  141. <Setter Property="Background" Value="{DynamicResource S.Brush.TextBackgroud.Default}"/>
  142. <Setter Property="BorderThickness" Value="0"/>
  143. <!--<Setter Property="BorderBrush" Value="{x:Null}"/>-->
  144. <Setter Property="HorizontalAlignment" Value="Stretch"/>
  145. <Setter Property="VerticalAlignment" Value="Center"/>
  146. <Setter Property="HorizontalContentAlignment" Value="Center"/>
  147. <Setter Property="VerticalContentAlignment" Value="Center"/>
  148. <!--<Setter Property="FocusVisualStyle" Value="{x:Null}"/>-->
  149. <Setter Property="Padding" Value="0" />
  150. <Setter Property="Width" Value="500" />
  151. <Setter Property="Height" Value="Auto" />
  152. <Setter Property="ItemsSource" Value="{Binding PropertyItemSource,Mode=TwoWay}" />
  153. <Setter Property="ItemsPanel">
  154. <Setter.Value>
  155. <ItemsPanelTemplate>
  156. <StackPanel/>
  157. </ItemsPanelTemplate>
  158. </Setter.Value>
  159. </Setter>
  160. <Setter Property="Template">
  161. <Setter.Value>
  162. <ControlTemplate TargetType="local:ObjectPropertyForm">
  163. <GroupBox Header="{TemplateBinding Title}">
  164. <Border HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
  165. VerticalAlignment="{TemplateBinding VerticalAlignment}"
  166. Background="{TemplateBinding Background}"
  167. BorderBrush="{TemplateBinding BorderBrush}"
  168. BorderThickness="{TemplateBinding BorderThickness}">
  169. <ItemsPresenter/>
  170. </Border>
  171. </GroupBox>
  172. </ControlTemplate>
  173. </Setter.Value>
  174. </Setter>
  175. </Style>

4、开放扩展

1、只需定义一个扩展类型,如:

/// <summary> 字符串属性类型 </summary>

    public class StringPropertyItem : ObjectPropertyItem<string>

    {

        public StringPropertyItem(PropertyInfo property, object obj) : base(property, obj)

        {

        }

    }

2、再添加一个DataTmeplate,如:

<DataTemplate DataType="{x:Type base:StringPropertyItem}">

        <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=local:ObjectPropertyForm},Path=Width-5}" 

              Height="35" Margin="5,0">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="*"/>

                <ColumnDefinition Width="Auto"/>

                <ColumnDefinition Width="2*"/>

                <ColumnDefinition Width="30"/>

            </Grid.ColumnDefinitions>

<TextBlock Text="{Binding Name}" 

                       FontSize="14" 

                       HorizontalAlignment="Center" 

                       VerticalAlignment="Center"/>

<TextBlock Text="{Binding Flag}" 

                       Grid.Column="1" Margin="5,0"

                       FontSize="14"  Foreground="{DynamicResource S.Brush.Red.Notice}" 

                       HorizontalAlignment="Right" 

                       VerticalAlignment="Center"/>

<local:FTextBox Text="{Binding Value,UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource DefaultTextBox}"

                     FontSize="14" Width="Auto" CaretBrush="Black"

                     Grid.Column="2" Height="30" base:ControlAttachProperty.FIcon=""

                     VerticalContentAlignment="Center" 

                     HorizontalAlignment="Stretch" VerticalAlignment="Center"/>

<TextBlock Text="" Grid.Column="3" Style="{DynamicResource FIcon }"

                       Foreground="{DynamicResource S.Brush.Red.Notice}" 

                       Visibility="{Binding Message,Converter={x:Static base:XConverter.VisibilityWithOutStringConverter},ConverterParameter={x:Null},Mode=TwoWay}"

                       FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"

                       HorizontalAlignment="Center" 

                       VerticalAlignment="Center"/>

        </Grid>

    </DataTemplate>

下载地址:https://github.com/HeBianGu/WPF-ControlBase.git

05-06 14:24