通过动态对象(DynamicObject)实现不定数量列的数据存储与展示

1 篇文章 0 订阅
1 篇文章 0 订阅

近来做项目遇到一个问题:需要将某个类的列表通过DataGrid进行展示,按照常规的做法,假设类名为T,T中实现如下:

class T
{
   private string _a;
   public string A
   {
     get{return _a;}
     set{_a = value;}
   }
}

列表对象为

List<T> TList= new List<T>();

DataGrid需要设定好列以及所需要绑定的属性名A,代码实现如下:

System.Windows.Controls.DataGrid dataGrid = new System.Windows.Controls.DataGrid();
System.Windows.Controls.DataGridTextColumn aColumn = new DataGridTextColumn();
aColumn.Header = "A";
aColumn.Binding = new System.Windows.Data.Binding("A");//绑定A
dataGrid .Columns.Add(aColumn);

再通过

dataGrid.ItemSource = TList;

即可。

    但是,如果dataGrid表格中需要展示的列(包括列名和数量)只有在运行时才能确定,而在编译期并不存在,那么该如何实现呢?

    比如,T中的属性数量和具体内容会根据用户实现的输入日期范围进行确定,日期范围如果是2017.1.1到2017.1.10,那么T中的属性就会有10个,并且画面上应该展示出10列分为为2017.1.1,2017.1.2...2017.1.10。日期范围如果是2017.1.1至2017.1.31,阿么T中的属性就有31个,画面上应该展示出31列数据。由此可见,类的属性在代码编写期根本就不知道,那么该如何进行实现呢?

    我的解决方案就是使用动态对象DynamicObject。具体含义及固定数量列的用法可自行百度。以下实现提供了更为复杂场景下的解决方案:类中的属性值又需要依赖于其他对象——初值取自指定对象,当指定对象变化时,该类中的值也发生变化并自动刷新画面数据。

    将T实现代码重新改装如下:

基础类M_DoubleValue实现:

    /// <summary>
    /// 自定义的数值类型,用以绑定和被绑定
    /// </summary>
    public class M_DoubleValueINotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public string ID = "";

        public readonly static DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(M_DoubleValue),new PropertyMetadata(OnValueChanged));

        public static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            M_DoubleValue valueObj = d as M_DoubleValue;

            if (valueObj.PropertyChanged != null)
                valueObj.PropertyChanged(this, new PropertyChangedEventArgs("Value"));
            
        }

        public double Value
        {
            set 
            { 
                this.SetValue(M_DoubleValue.ValueProperty, value);
                PC("Value");
            }
            get { return (double)this.GetValue(M_DoubleValue.ValueProperty); }
        }

        private Binding _bindingValue;
        public Binding BindingValue
        {
            get
            {
                if(_bindingValue == null)
                {
                    _bindingValue = new Binding("Value") { Source = this,NotifyOnTargetUpdated = true,NotifyOnSourceUpdated = true };
                }

                return _bindingValue;
            }
        }

    }

 类T实现:

    /// <summary>
    /// T类型
    /// </summary>
    public class T: DynamicObject, INotifyPropertyChanged
    {
        Dictionary<string, M_DoubleValue> Properties = new Dictionary<string, M_DoubleValue>();

        public event PropertyChangedEventHandler PropertyChanged;

        protected void PC(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public void SetMemberBinding(string dateStr, Binding binding)
        {
            M_DoubleValue value = new M_DoubleValue();
            value.Key = dateStr;
            value.SetBinding(M_DoubleValue.ValueProperty, binding);
            //刷新Grid方式
            value.PropertyChanged += value_PropertyChanged;

            Properties[date.Value] = value;
        }

        //当value值更新时,通知的是绑定到列上的ID
        void value_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            PC((sender as M_DoubleValue).ID);
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            
            return true;
        }
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {

            M_DoubleValue value;
            Properties.TryGetValue(binder.Name, out value);
            result = value.Value;
            return true;
        }
    }

 客户端调用:

    System.Windows.Controls.DataGrid datagrid = new System.Windows.Controls.DataGrid();
    datagrid .AutoGenerateColumns = false;            

    List<T> TList= new List<T>();
    //this.AreaPlan.UnitList业务对象
    foreach(M_Unit unit in this.AreaPlan.UnitList)
    {
        T t= new T();
        //遍历日期,形成动态列
        foreach (M_Date date in this.AreaPlan.PlanCalendar)
        {
            t.SetMemberBinding(date.Value, unit.Produce.ProduceCalendar[date].BindingPlanProduction);
        }
            TList.Add(t);
    }

    foreach(M_Date date in this.AreaPlan.PlanCalendar)
    {
        System.Windows.Controls.DataGridTextColumn dateColumn = new DataGridTextColumn();
        dateColumn.Header =  date.ValueDT.Month + "/" + date.ValueDT.Day;
        dateColumn.Binding = new System.Windows.Data.Binding(date.Value) { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged};
        dataGrid.Columns.Add(dateColumn);
    }

    dataGrid.ItemsSource = TList;

如此即可显示指定日期范围内的数据,并可与业务数据源绑定,保证画面数据的实时性。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值