示例:WPF開發的簡單ObjectProperyForm用來綁定實體表單

一、目的:自定義控件,用來直接綁定實體數據,簡化開發週期

二、實現:

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="[email protected]" 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="&#xe626;" 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="&#xe626;" 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="&#xe626;" 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="&#xe626;" 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="&#xe626;" 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="&#xe626;" 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章