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);
以上实现方式参考了网上若干资料,具体网址没有保存下来,无法提供链接,希望原作者见谅!