一、目的:自定义控件,用来直接绑定实体数据,简化开发周期
二、实现:
1、绑定实体对象
2、通过特性显示属性名称
3、通过特性增加验证条件
4、已经实现String、Int、Double、DateTime、Bool几种简单类型的DataTemplate模板,其他模板支持扩展
5、其他后续更新...
三、示例:
实体定义如下:
- public class Student
- {
- [Display("姓名")]
- [Required]
- public string Name { get; set; }
-
- [Display("班级")]
- [Required]
- public string Class { get; set; }
-
- [Display("地址")]
- [Required]
- public string Address { get; set; }
-
- [Display("邮箱")]
- [Required]
- public string Emall { get; set; }
-
- [Display("可用")]
- [Required]
- public bool IsEnbled { get; set; }
-
- [Display("时间")]
- [Required]
- public DateTime time { get; set; }
-
- [Display("年龄")]
- [Required]
- public int Age { get; set; }
-
- [Display("平均分")]
- public double Score { get; set; }
-
- [Display("电话号码")]
- [Required]
- [RegularExpression(@"^1[3|4|5|7|8][0-9]{9}$", ErrorMessage = "手机号码不合法!")]
- public string Tel { get; set; }
- }
DisplayAttribute:用来标识显示名称
ResuiredAttribute:用来标识数据不能为空
RgularExpression:引用正则表达式验证数据是否匹配
其他特性后续更新...
应用方式:
-
- <UserControl.Resources>
- <local:Student x:Key="S.Student.HeBianGu"
- Name="河边骨"
- Address="四川省成都市高新区"
- Class="四年级"
- Emall="7777777777@QQ.com" Age="33" Score="99.99" IsEnbled="True" time="2019-09-09"/>
- </UserControl.Resources>
-
- <wpfcontrollib:ObjectPropertyForm Grid.Row="1" Title="学生信息" SelectObject="{StaticResource S.Student.HeBianGu}" >
- <base:Interaction.Behaviors>
- <base:MouseDragElementBehavior ConstrainToParentBounds="True"/>
- <base:SelectZIndexElementBehavior/>
- </base:Interaction.Behaviors>
四、代码
1、通过反射获取属性和特性
- ObservableCollection<ObjectPropertyItem> PropertyItemSource
- {
- get { return (ObservableCollection<ObjectPropertyItem>)GetValue(PropertyItemSourceProperty); }
- set { SetValue(PropertyItemSourceProperty, value); }
- }
-
- // Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
- public static readonly DependencyProperty PropertyItemSourceProperty =
- DependencyProperty.Register("PropertyItemSource", typeof(ObservableCollection<ObjectPropertyItem>), typeof(ObjectPropertyForm), new PropertyMetadata(new ObservableCollection<ObjectPropertyItem>(), (d, e) =>
- {
- ObjectPropertyForm control = d as ObjectPropertyForm;
-
- if (control == null) return;
-
- ObservableCollection<ObjectPropertyItem> config = e.NewValue as ObservableCollection<ObjectPropertyItem>;
-
- }));
-
-
- void RefreshObject(object o)
- {
- Type type = o.GetType();
-
- var propertys = type.GetProperties();
-
- this.PropertyItemSource.Clear();
-
- foreach (var item in propertys)
- {
- var from = ObjectPropertyFactory.Create(item, o);
-
- this.PropertyItemSource.Add(from);
- }
-
- this.ItemsSource = this.PropertyItemSource;
- }
2、定义类型基类、扩展之类和工厂方法
- /// <summary> 类型基类 </summary>
- public class ObjectPropertyItem : NotifyPropertyChanged
- {
- public string Name { get; set; }
- public PropertyInfo PropertyInfo { get; set; }
-
- public object Obj { get; set; }
- public ObjectPropertyItem(PropertyInfo property, object obj)
- {
- PropertyInfo = property;
-
-
- var display = property.GetCustomAttribute<DisplayAttribute>();
-
- Name = display == null ? property.Name : display.Name;
-
- Obj = obj;
- }
-
-
- }
-
- /// <summary> 泛型类型基类 </summary>
- public class ObjectPropertyItem<T> : ObjectPropertyItem
- {
- private T _value;
- /// <summary> 说明 </summary>
- public T Value
- {
- get { return _value; }
- set
- {
-
- this.Message = null;
-
- // Do:检验数据有效性
- if (Validations != null)
- {
- foreach (var item in Validations)
- {
- if (!item.IsValid(value))
- {
- this.Message = item.ErrorMessage;
- }
- }
- }
-
- _value = value;
-
- RaisePropertyChanged("Value");
-
- this.SetValue(value);
- }
- }
-
- void SetValue(T value)
- {
- this.PropertyInfo.SetValue(Obj, value);
- }
-
- List<ValidationAttribute> Validations { get; }
-
- public ObjectPropertyItem(PropertyInfo property, object obj) : base(property, obj)
- {
- Value = (T)property.GetValue(obj);
-
- Validations = property.GetCustomAttributes<ValidationAttribute>()?.ToList();
-
- if(Validations!=null&& Validations.Count>0)
- {
- this.Flag = "*";
- }
- }
-
-
-
- private string _message;
- /// <summary> 说明 </summary>
- public string Message
- {
- get { return _message; }
- set
- {
- _message = value;
- RaisePropertyChanged("Message");
- }
- }
-
- public string Flag { get; set; }
-
- }
-
- /// <summary> 字符串属性类型 </summary>
- public class StringPropertyItem : ObjectPropertyItem<string>
- {
- public StringPropertyItem(PropertyInfo property, object obj) : base(property, obj)
- {
- }
- }
-
- /// <summary> 时间属性类型 </summary>
- public class DateTimePropertyItem : ObjectPropertyItem<DateTime>
- {
- public DateTimePropertyItem(PropertyInfo property, object obj) : base(property, obj)
- {
- }
- }
-
- /// <summary> Double属性类型 </summary>
- public class DoublePropertyItem : ObjectPropertyItem<double>
- {
- public DoublePropertyItem(PropertyInfo property, object obj) : base(property, obj)
- {
- }
- }
-
- /// <summary> Int属性类型 </summary>
-
- public class IntPropertyItem : ObjectPropertyItem<int>
- {
- public IntPropertyItem(PropertyInfo property, object obj) : base(property, obj)
- {
- }
- }
-
- /// <summary> Bool属性类型 </summary>
- public class BoolPropertyItem : ObjectPropertyItem<bool>
- {
- public BoolPropertyItem(PropertyInfo property, object obj) : base(property, obj)
- {
- }
- }
类型工厂:
- public class ObjectPropertyFactory
- {
- public static ObjectPropertyItem Create(PropertyInfo info, object obj)
- {
- if (info.PropertyType == typeof(int))
- {
- return new IntPropertyItem(info, obj);
- }
- else if (info.PropertyType == typeof(string))
- {
- return new StringPropertyItem(info, obj);
- }
- else if (info.PropertyType == typeof(DateTime))
- {
- return new DateTimePropertyItem(info, obj);
- }
- else if (info.PropertyType == typeof(double))
- {
- return new DoublePropertyItem(info, obj);
- }
- else if (info.PropertyType == typeof(bool))
- {
- return new BoolPropertyItem(info, obj);
- }
-
- return null;
- }
- }
3、样式模板
- <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>
-
- <DataTemplate DataType="{x:Type base:BoolPropertyItem}">
- <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"/>
- <CheckBox IsChecked="{Binding Value}" FontSize="14" Grid.Column="2" Height="30"
- VerticalContentAlignment="Center"
- HorizontalAlignment="Left" 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}}"
- FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"
- HorizontalAlignment="Center"
- VerticalAlignment="Center"/>
- </Grid>
- </DataTemplate>
-
- <DataTemplate DataType="{x:Type base:DateTimePropertyItem}">
- <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"/>
- <DatePicker SelectedDate="{Binding Value}" FontSize="14" Grid.Column="2" Height="30"
- VerticalContentAlignment="Center" Width="Auto"
- 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}}"
- FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"
- HorizontalAlignment="Center"
- VerticalAlignment="Center"/>
- </Grid>
- </DataTemplate>
-
- <DataTemplate DataType="{x:Type base:IntPropertyItem}">
- <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"/>
- <Slider Value="{Binding Value}" FontSize="14" Grid.Column="2" Height="30"
- 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}}"
- FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"
- HorizontalAlignment="Center"
- VerticalAlignment="Center"/>
- </Grid>
- </DataTemplate>
-
- <DataTemplate DataType="{x:Type base:DoublePropertyItem}">
- <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"/>
- <Slider Value="{Binding Value}" FontSize="14" Grid.Column="2" Height="30"
- 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}}"
- FontSize="14" TextTrimming="CharacterEllipsis" ToolTip="{Binding Message}"
- HorizontalAlignment="Center"
- VerticalAlignment="Center"/>
- </Grid>
- </DataTemplate>
-
- <Style TargetType="local:ObjectPropertyForm">
- <Setter Property="Background" Value="{DynamicResource S.Brush.TextBackgroud.Default}"/>
- <Setter Property="BorderThickness" Value="0"/>
- <!--<Setter Property="BorderBrush" Value="{x:Null}"/>-->
- <Setter Property="HorizontalAlignment" Value="Stretch"/>
- <Setter Property="VerticalAlignment" Value="Center"/>
- <Setter Property="HorizontalContentAlignment" Value="Center"/>
- <Setter Property="VerticalContentAlignment" Value="Center"/>
- <!--<Setter Property="FocusVisualStyle" Value="{x:Null}"/>-->
- <Setter Property="Padding" Value="0" />
- <Setter Property="Width" Value="500" />
- <Setter Property="Height" Value="Auto" />
- <Setter Property="ItemsSource" Value="{Binding PropertyItemSource,Mode=TwoWay}" />
- <Setter Property="ItemsPanel">
- <Setter.Value>
- <ItemsPanelTemplate>
- <StackPanel/>
-
- </ItemsPanelTemplate>
- </Setter.Value>
- </Setter>
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="local:ObjectPropertyForm">
- <GroupBox Header="{TemplateBinding Title}">
- <Border HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
- VerticalAlignment="{TemplateBinding VerticalAlignment}"
- Background="{TemplateBinding Background}"
- BorderBrush="{TemplateBinding BorderBrush}"
- BorderThickness="{TemplateBinding BorderThickness}">
- <ItemsPresenter/>
- </Border>
- </GroupBox>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </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