佳月金属制品厂 发表于 2024-3-30 23:42:49

一个可以让你有更多时间摸鱼的WPF控件(二)

前言
  上文介绍了如何通过一个Form自定义控件来简化数据的录入,并自动实现数据校验,自动布局排列等功能。本文继续介绍如何优化表格控件的使用,缩减代码量,实现工作效率的提升。
一、功能实现
    上文中分析了DataGrid跟ListView两种表格控件的优劣,在这里我们选择ListView来实现我们的表格功能,如有疑问请看上一篇文章,这里不再赘述。
 下面我们定义一个ListViewExtensions静态类来实现ListView的附加属性,并在附加属性更改后实现ListView的优化功能。
public static class ListViewExtensions
    {
      #region AutoGenerateColumns
      public static readonly DependencyProperty AutoGenerateColumnsProperty =
            DependencyProperty.RegisterAttached("AutoGenerateColumns", typeof(bool), typeof(ListViewExtensions), new PropertyMetadata(false, AutoGenerateColumnsChanged));

      public static bool GetAutoGenerateColumns(DependencyObject obj)
      {
            return (bool)obj.GetValue(AutoGenerateColumnsProperty);
      }

      public static void SetAutoGenerateColumns(DependencyObject obj, bool value)
      {
            obj.SetValue(AutoGenerateColumnsProperty, value);
      }

      private static void AutoGenerateColumnsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
      {
            ListView listView = obj as ListView;
            bool autoGenerateColumns = (bool)e.NewValue;

            if (listView != null)
            {
                if (autoGenerateColumns)
                {
                  listView.Loaded += ListViewLoadedHandler;

                }
                else
                {
                  listView.Loaded -= ListViewLoadedHandler;
                }
            }
      }

      private static void ListViewLoadedHandler(object sender, RoutedEventArgs e)
      {
            var listView = (ListView)sender;
            if (listView.ItemsSource == null) return;

            var itemType = listView.ItemsSource.GetType().GetGenericArguments().FirstOrDefault();
            if (itemType != null)
            {
                // 获取数据源的属性信息
                var properties = itemType.GetProperties();
                GridView gridView = null;
                if (listView.View is GridView gv)
                {
                  gridView = gv;
                }
                else
                {
                  listView.View = gridView = new GridView();
                }

                // 根据属性信息创建列并添加到 GridView 中
                var optionMappingConverter = new OptionMappingConverter();
                var enumDescriptionConverter = new EnumDescriptionConverter();
                foreach (PropertyInfo property in properties)
                {
                  //排除无用属性
                  var name = property.Name;
                  if (PropertyHelper.IgnoredProperties.Contains(property.Name)) continue;

                  //读取列参数
                  var columnAttribute = property.GetCustomAttributes().OfType<ColumnAttribute>().FirstOrDefault();
                  if (columnAttribute == null || !columnAttribute.IsVisible) continue;

                  //排除重复属性
                  var targetColumn = gridView.Columns.FirstOrDefault(item => GetColumnName(item) == property.Name);
                  if (targetColumn != null)
                  {
                        if (targetColumn.Header == null)
                            targetColumn.Header = columnAttribute.Name;
                        SetColumnIndex(targetColumn, columnAttribute.Order);
                        continue;
                  }

                  var column = new GridViewColumn() { Header = !string.IsNullOrEmpty(columnAttribute.Name) ? columnAttribute.Name : name };
                  SetColumnName(column, property.Name);
                  //分组
                  if (columnAttribute is GroupColumnAttribute group) ListViewExtensions.SetGroup(column, group.Group);
                  //宽度
                  if (columnAttribute.Width > 0) column.Width = columnAttribute.Width;
                  //转换器
                  if (columnAttribute.Converter != null)
                  {
                        column.DisplayMemberBinding = new Binding(property.Name)
                        {
                            Converter = Activator.CreateInstance(columnAttribute.Converter) as IValueConverter,
                            ConverterParameter = columnAttribute.ConverterParameter,
                            StringFormat = columnAttribute.StringFormat
                        };
                  }
                  else
                  {
                        //指定转换器
                        var optionMappingAttribute = property.GetCustomAttributes().OfType<OptionMappingAttribute>().FirstOrDefault();
                        if (optionMappingAttribute != null)
                        {
                            column.DisplayMemberBinding = new Binding(property.Name)
                            {
                              Converter = optionMappingConverter,
                              ConverterParameter = optionMappingAttribute.Mapping
                            };
                        }
                        else if (property.PropertyType.IsEnum)
                        {
                            column.DisplayMemberBinding = new Binding(property.Name)
                            {
                              Converter = enumDescriptionConverter,
                              StringFormat = columnAttribute.StringFormat
                            };
                        }
                        else
                        {
                            column.DisplayMemberBinding = new Binding(property.Name) { StringFormat = columnAttribute.StringFormat };
                        }
                  }

                  SetColumnIndex(column, columnAttribute.Order);
                  gridView.Columns.Add(column);
                }

                var cols = gridView.Columns.OrderBy(item => GetColumnIndex(item)).ToArray();
                gridView.Columns.Clear();
                foreach (var col in cols)
                {
                  gridView.Columns.Add(col);
                }
            }
      }
      #endregion

      #region ColumnIndex
      public static int GetColumnIndex(DependencyObject obj)
      {
            return (int)obj.GetValue(ColumnIndexProperty);
      }

      public static void SetColumnIndex(DependencyObject obj, int value)
      {
            obj.SetValue(ColumnIndexProperty, value);
      }

      public static readonly DependencyProperty ColumnIndexProperty =
            DependencyProperty.RegisterAttached("ColumnIndex", typeof(int), typeof(ListViewExtensions), new PropertyMetadata(0));

      #endregion

      #region ColumnName
      public static string GetColumnName(DependencyObject obj)
      {
            return (string)obj.GetValue(ColumnNameProperty);
      }

      public static void SetColumnName(DependencyObject obj, string value)
      {
            obj.SetValue(ColumnNameProperty, value);
      }


      public static readonly DependencyProperty ColumnNameProperty =
            DependencyProperty.RegisterAttached("ColumnName", typeof(string), typeof(ListViewExtensions));
      #endregion

      #region Group
      public static string GetGroup(DependencyObject obj)
      {
            return (string)obj.GetValue(GroupProperty);
      }

      public static void SetGroup(DependencyObject obj, string value)
      {
            obj.SetValue(GroupProperty, value);
      }

      public static readonly DependencyProperty GroupProperty =
            DependencyProperty.RegisterAttached("Group", typeof(string), typeof(ListViewExtensions));

      #endregion
    }二、示例代码
View
Model
public class Person : ValidationObjectBase
    {
      private string _name;
      private DateTime _dateOfBirth = DateTime.Now;
      private int _age;
      private int _gender = 1;
      private string _phoneNumber;
      private string _email;
      private string _address;
      private string _idCardNumber;
      private EducationInfo _education;
      private MaritalStatus _maritalStatus;

      /// <summary>
      /// 姓名
      /// </summary>
      
      public string Name
      {
            get => _name;
            set => this.SetProperty(ref _name, value);
      }

      /// <summary>
      /// 出生日期
      /// </summary>
      
      public DateTime DateOfBirth
      {
            get => _dateOfBirth;
            set => this.SetProperty(ref _dateOfBirth, value);
      }

      /// <summary>
      /// 年龄
      /// </summary>
      
      public int Age
      {
            get => _age;
            set => this.SetProperty(ref _age, value);
      }

      /// <summary>
      /// // 性别
      /// </summary>
      
      public int Gender
      {
            get => _gender;
            set => this.SetProperty(ref _gender, value);
      }

      /// <summary>
      /// 手机号码
      /// </summary>
      
      public string PhoneNumber
      {
            get => _phoneNumber;
            set => this.SetProperty(ref _phoneNumber, value);
      }

      /// <summary>
      /// 电子邮箱
      /// </summary>
      
      public string Email
      {
            get => _email;
            set => this.SetProperty(ref _email, value);
      }

      /// <summary>
      /// 地址信息
      /// </summary>
      
      public string Address
      {
            get => _address;
            set => this.SetProperty(ref _address, value);
      }

      /// <summary>
      /// 身份证号码
      /// </summary>
      
      public string IdCardNumber
      {
            get => _idCardNumber;
            set => this.SetProperty(ref _idCardNumber, value);
      }

      /// <summary>
      /// 教育信息
      /// </summary>
      //
      public EducationInfo Education
      {
            get => _education;
            set => this.SetProperty(ref _education, value);
      }

      /// <summary>
      /// 婚姻状况
      /// </summary>
      
      public MaritalStatus MaritalStatus
      {
            get => _maritalStatus;
            set => this.SetProperty(ref _maritalStatus, value);
      }<br>}ViewModel
public class FormDemoViewModel : BindableBase
    {
      public ObservableCollection<Person> Collection
      {
            get { return _collection; }
            set { this.SetProperty(ref _collection, value); }
      }
    }
 三、答疑解惑
2.1 如何添加自定义列?
答:可以按常规方式添加自定义列,用ListViewExtensions.ColumnIndex来指定位的位置,以下为示例代码。
<ListView extensions:ListViewExtensions.AutoGenerateColumns="True" ItemsSource="{Binding Collection}">
    <GridView>
      <GridViewColumn extensions:ListViewExtensions.ColumnIndex="0">
            <GridViewColumn.Header>
                <CheckBox Content="全选" />
            </GridViewColumn.Header>
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                  <CheckBox />
                </DataTemplate>
            </GridViewColumn.CellTemplate>
      </GridViewColumn>
    </GridView>
</ListView>2.2 如何自动生成的列不满足需求,可不可以自己定义列?
答:可以,使用ListViewExtensions.ColumnName属性可以覆盖某一个列的自动生成的操作。
<ListView extensions:ListViewExtensions.AutoGenerateColumns="True" ItemsSource="{Binding Collection}">
    <GridView>
      <GridViewColumn
                  extensions:ListViewExtensions.ColumnIndex="1"
                  extensions:ListViewExtensions.ColumnName="Name">
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                  <TextBlock Text="{Binding Name}" />
                </DataTemplate>
            </GridViewColumn.CellTemplate>
      </GridViewColumn>
    </GridView>
</ListView>2.3 如何给列设置顺序?
答:在属性上给ColumnAttribute特性设置参数Order。

public DateTime DateOfBirth
{
      get => _dateOfBirth;
      set => this.SetProperty(ref _dateOfBirth, value);
}2.4 如何设置列的宽度?
答:在属性上给ColumnAttribute特性设置参数Width。

public DateTime DateOfBirth
{
      get => _dateOfBirth;
      set => this.SetProperty(ref _dateOfBirth, value);
}2.5 如何将列设为不可见?
答:在属性上给ColumnAttribute特性设置参数IsVisible。

public DateTime DateOfBirth
{
       get => _dateOfBirth;
       set => this.SetProperty(ref _dateOfBirth, value);
}2.6 如何给绑定设置格式化字符串?
答:在属性上给ColumnAttribute特性设置参数StringFormat。

public DateTime DateOfBirth
{
      get => _dateOfBirth;
      set => this.SetProperty(ref _dateOfBirth, value);
}2.7 如何给绑定设置转换器及参数?
答:在属性上给ColumnAttribute特性设置Converter和ConverterParameter参数。

public DateTime DateOfBirth
{
      get => _dateOfBirth;
      set => this.SetProperty(ref _dateOfBirth, value);


来源:https://www.cnblogs.com/qushi2020/p/18106033
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 一个可以让你有更多时间摸鱼的WPF控件(二)