2016-11-23 59 views
-1

我想使用mvvm動態生成數據網格。在數據網格的每個單元格中,我必須顯示一個對象。列名是對象的屬性之一。 datagrid的Itemsource將成爲對象列表。如何使用mvvm動態生成數據網格?使用mvvm在wpf數據網格中生成列的動態方式

更新

我創建了一直延伸usiing ICustomTypeDescriptor的自定義類。

public class MyCustomType : ICustomTypeDescriptor 
    { 
    // This is instance data. 
    private readonly BindingList<PropertyDescriptor> _propertyDescriptors = new BindingList<PropertyDescriptor>(); 

    // The data is stored on the type instance. 
    private readonly IDictionary<string, object> _propertyValues = new Dictionary<string, object>(); 

    // The property descriptor now takes an extra argument. 
    public void AddProperty(string name, Type type) 
    { 
     _propertyDescriptors.Add(new MyPropertyDescriptor(name, type)); 
    } 

    public PropertyDescriptorCollection GetProperties() 
    { 
     return new PropertyDescriptorCollection(_propertyDescriptors.ToArray()); 
    } 

    public PropertyDescriptorCollection GetProperties(Type type) 
    { 
     return new PropertyDescriptorCollection(_propertyDescriptors.ToArray()); 
    } 

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     return GetProperties(); 
    } 

    public object GetPropertyOwner(PropertyDescriptor pd) 
    { 
     throw new NotImplementedException(); 
    } 

    public AttributeCollection GetAttributes() 
    { 
     throw new NotImplementedException(); 
    } 

    public string GetClassName() 
    { 
     throw new NotImplementedException(); 
    } 

    public string GetComponentName() 
    { 
     throw new NotImplementedException(); 
    } 

    public TypeConverter GetConverter() 
    { 
     throw new NotImplementedException(); 
    } 

    public EventDescriptor GetDefaultEvent() 
    { 
     throw new NotImplementedException(); 
    } 

    public PropertyDescriptor GetDefaultProperty() 
    { 
     throw new NotImplementedException(); 
    } 

    public object GetEditor(Type editorBaseType) 
    { 
     throw new NotImplementedException(); 
    } 

    public EventDescriptorCollection GetEvents() 
    { 
     return null; 
    } 

    public EventDescriptorCollection GetEvents(Attribute[] attributes) 
    { 
     return null; 
    } 

    private class MyPropertyDescriptor : PropertyDescriptor 
    { 
     // This data is here to indicate that different instances of the type 
     // object may have properties of the same name, but with different 
     // characteristics. 
     private readonly Type _type; 

     public MyPropertyDescriptor(string name, Type type) 
      : base(name, null) 
     { 
      _type = type; 
     } 

     public override bool CanResetValue(object component) 
     { 
      throw new NotImplementedException(); 
     } 

     public override Type ComponentType 
     { 
      get { throw new NotImplementedException(); } 
     } 

     public override object GetValue(object component) 
     { 
      MyCustomType obj = (MyCustomType) component; 
      object value = null; 
      obj._propertyValues.TryGetValue(Name, out value); 
      return value; 
     } 

     public override bool IsReadOnly 
     { 
      get { return false; } 
     } 

     public override Type PropertyType 
     { 
      get { return _type; } 
     } 

     public override void ResetValue(object component) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void SetValue(object component, object value) 
     { 
      var oldValue = GetValue(component); 

      if (oldValue != value) 
      { 
       MyCustomType obj = (MyCustomType) component; 
       obj._propertyValues[Name] = value; 
       OnValueChanged(component, new PropertyChangedEventArgs(Name)); 
      } 
     } 

     public override bool ShouldSerializeValue(object component) 
     { 
      throw new NotImplementedException(); 
     } 

     public override void AddValueChanged(object component, EventHandler handler) 
     { 
      // set a breakpoint here to see WPF attaching a value changed handler 
      base.AddValueChanged(component, handler); 
     } 
    } 
} 

我米結合本customtype對象的列表到數據網格的ItemSource。但datagrid沒有顯示任何內容?

回答

0

使用DataGrid的方式是將IEnumerable<T>作爲其ItemsSource,其中T是具有您希望爲其生成列的屬性的類或接口。您應該使用DataGrid支持的類型。大多數值類型都受支持。您可以找到關於支持的類型以及用法的列表HERE

所以你的列表應該包含行的對象,而不是單元格。 DataGrid將爲列表的通用參數類型的每個公共屬性自動生成單元格。

然後可以使用MVVM到列表綁定如下:

<DataGrid ItemsSource="{Binding MyList}" AutoGenerateColumns="True"></DataGrid> 

當然DataGrid的DataContext的(無論是繼承或顯式)應包含項目的public IEnumerable<T> MyList { get; }

UPDATE

其實反過來每一行對象具有細胞的對象名單。 每個單元格對象都有多個屬性。我想將 屬性值中的一個顯示爲列名稱,並且每個單元格對象將根據對象的類型具有不同的 單元格樣式。如何動態創建具有這些條件的數據網格 ?

在WPF中,DataGrid對每一行都有相同的列集。所以,就你的情況而言,即使你可以爲每個單元定義不同的列數據,你也可以只使用第一行(或者你需要的那一行)來定義列。我寧願建議創建Custom Attributes以聲明列屬性(數據類型,header..etc),因爲它是一個聲明性信息而不是動態的(不應逐行更改或每次形成一次)。使用THIS線程中描述的觸發器,樣式信息仍然可以具有一定的活力。這更像是一種WPF方式。

無論如何,如果你想堅持你的模式,你應該在派生自DataGrid的類中實現列探索邏輯。在ItemsSourceChanged處理程序中,檢查ItemsSource的類型。如果這是一個IEnumerable,那麼通過反射就可以得到泛型參數(T),並檢查該類型是否支持列描述模式。例如:

protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue) 
{ 
    base.OnItemsSourceChanged(oldValue, newValue); 

    if (AutoGenerateColumns && newValue != null && newValue.GetType().IsGenericType) 
    { 
     this.Columns.Clear(); 

     var type = newValue.GetType().GetGenericArguments().First(); 

     if (typeof(IMyColumnDescriptionStructure).IsAssignableFrom(type)) 
     { 
      var rows = newValue as IEnumerable<IMyColumnDescriptionStructure>; 
      var firstRow = rows.First() as IMyColumnDescriptionStructure; 

      // TODO: explore your structure and add column definitions 
      ///this.Columns.Add(...) 
     } 
    } 
} 
+0

感謝Daniel,實際上每個行對象都有單元的對象列表。每個單元格對象都有多個屬性。我想顯示屬性值的1作爲列名稱,每個單元格對象將根據對象的類型具有不同的單元格樣式。如何動態創建具有這些條件的數據網格? – Rony