DataGrid中动态添加列

     最近在项目中碰到了这样一个场景:DataGrid需要绑定到一个ObservableCollection<MyClass>,MyClass包含了一组对象,每个对象对应DataGrid的一个Column,如果把这一组对象放进MyClass的一个ObservableCollection<>属性中,则无法绑定;如果每个对象做为MyClass的一个属性,则可以动态创建Column并绑定到属性。因此我们需要能为MyClass动态添加属性,使用dynamic类型是个不错的选择。实现步骤如下:

   1、  首先定义属性

        public ObservableCollection<dynamic> DisplayPlanList {get;set;}

        并绑定到DataGrid,PlanGrid.ItemsSource = DisplayPlanList;

   2、 定义一个DynamicObject类

public class DynamicObjectClass : DynamicObject, INotifyPropertyChanged
{
#region DynamicObject overrides

public DynamicObjectClass()
{
}

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return members.TryGetValue(binder.Name, out result);
}

public override bool TrySetMember(SetMemberBinder binder, object value)
{
members[binder.Name] = value;
OnPropertyChanged(binder.Name);
return true;
}

public override IEnumerable<string> GetDynamicMemberNames()
{
return members.Keys;
}

public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
int index = (int)indexes[0];
try
{
result = itemsCollection[index];
}
catch (ArgumentOutOfRangeException)
{
result = null;
return false;
}
return true;
}

public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
int index = (int)indexes[0];
itemsCollection[index] = value;
OnPropertyChanged(System.Windows.Data.Binding.IndexerName);
return true;
}

public override bool TryDeleteMember(DeleteMemberBinder binder)
{
if (members.ContainsKey(binder.Name))
{
members.Remove(binder.Name);
return true;
}
return false;
}

public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes)
{
int index = (int)indexes[0];
itemsCollection.RemoveAt(index);
return true;
}

#endregion DynamicObject overrides

#region INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged;

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

#endregion INotifyPropertyChanged

#region Public methods

public object AddItem(object item)
{
itemsCollection.Add(item);
OnPropertyChanged(Binding.IndexerName);
return null;
}

#endregion Public methods

#region Private data

Dictionary<string, object> members = new Dictionary<string, object>();
ObservableCollection<object> itemsCollection = new ObservableCollection<object>();

#endregion Private data
}


public class SetPropertyBinder : SetMemberBinder
{
public SetPropertyBinder(string propertyName)
: base(propertyName, false) { }

public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
{
return new DynamicMetaObject(
System.Linq.Expressions.Expression.Throw(
System.Linq.Expressions.Expression.New(
typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }),
new System.Linq.Expressions.Expression[] { System.Linq.Expressions.Expression.Constant("Error") }),
this.ReturnType), BindingRestrictions.Empty);
}
}

public class GetPropertyBinder : GetMemberBinder
{
public GetPropertyBinder(string propertyName)
: base(propertyName, false) { }

public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject value)
{
return new DynamicMetaObject(
System.Linq.Expressions.Expression.Throw(
System.Linq.Expressions.Expression.New(
typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }),
new System.Linq.Expressions.Expression[] { System.Linq.Expressions.Expression.Constant("Error") }),
this.ReturnType), BindingRestrictions.Empty);
}
}

该类继承自DynamicObject,主要提供了设置属性、获取属性功能。

3、 为DataGrid动态添加列

dynamic item = new DynamicObjectClass();
item.ID = Guid.NewGuid();
item.Name = "名称#";
ObjectList.Add(item);
PlanGrid.Columns.Add(new DataGridTextColumn() { Header = "编号", Binding = new Binding("ID") });
PlanGrid.Columns.Add(new DataGridTextColumn() { Header = "名称", Binding = new Binding("Name") });

上面代码中的ID、Name是硬编码设置的属性,也可以根据参数动态设置属性,如下:

foreach (DynamicObjectClass obj in ObjectList)
{
obj.TrySetMember(new SetPropertyBinder(propName), bindingData);
}

上面代码的意思是为每个DynamicObject添加一个名为propName的属性,并绑定到bindingData对象。其中每个DynamicObject对应DataGrid的一行,propName对应DataGrid

的一列,可按如下方式为DataGrid添加一列:

DataGridTextColumn column = new DataGridTextColumn();

string propName = "New Column";

column.Binding = new Binding(propName);

PlanGrid.Columns.Add(column);

如果需要可通过以下方式获取某个属性对应的绑定值:

object ID;
obj.TryGetMember(new GetPropertyBinder("ID"), out ID);


以上实现方式参考了网上若干资料,具体网址没有保存下来,无法提供链接,希望原作者见谅!





posted on 2011-12-21 19:15  顾文锦  阅读(1146)  评论(0编辑  收藏  举报