2016-11-12 1 views
1

DataGridView을 사용하여 Windows Forms에 Dictionary<string, TData>을 표시하려고합니다. 그 특정한 유스 케이스는 다음과 같다. 사전 키는 열 이름이고 월을 나타내고 데이터 유형은 십진수이다.DataGridView를 사용하여 사전을 표시하는 방법은 무엇입니까?

그래서 각 열에 대해 한 달과 해당하는 십진수가 있습니다. DataGridView에서 해당 달의 열을 표시하고 사전 항목에 데이터 바인딩을 수행하기를 원했습니다.

분명히 다른 해결책이 있습니다. 12 개의 속성을 포함하는 뷰 모델을 만듭니다. 각 속성은 매월 10 진수입니다. DataGridView를 만들고이 뷰 모델 개체의 목록 인 데이터 원본을 사용하여이 뷰 모델에 대한 일반적인 데이터 바인딩을 수행합니다.

하지만 지루합니다. 사전을 사용하여 자동화 할 수있는 것들을 만들어야합니다.

제 문제는 사전을 기반으로 동적으로 열을 만들어야하고 데이터 바인딩이 그런 방식으로 수행되어야한다는 것입니다.

나는 조금 봤 거든 바인딩을 만들 수있는 Binding 클래스를 발견. 하지만 동적으로 생성 된 열을 사전의 항목에 바인딩하는 방법을 모르겠습니다.

어떻게이 작업을 수행 할 수 있습니까?

+0

는 또한 [이 게시물] (HTTP를 살펴 : // 유래합니다. com/a/42611427/3110834). –

답변

2

사전을 DataGridView 또는 PropertyGrid에서 편집하려면 ICustomTypeDescriptor을 구현해야합니다.

옵션 1 - 구현은 ICustomTypeDescriptor 당신은 ICustomTypeDescriptor을 구현 한 다음 DataGridView에서 사전을 편집 할 수 있습니다

. 약간의 변경으로 this 구현을 사용할 수 있습니다.

Dictionary<string, int> dictionary; 
public void Form1_Load(object sender, EventArgs e) 
{ 
    dictionary = new Dictionary<string, int>() { { "A", 1 }, { "B", 2 }, { "C", 3 } }; 
    dataGridView1.DataSource = new BindingSource(new DictionaryAdapter(dictionary) , ""); 
} 

또는 당신이 선호하는 경우에, 당신은 PropertyGridSelectedObject로 설정할 수 있습니다 :

public class DictionaryAdapter : ICustomTypeDescriptor 
{ 
    IDictionary dictionary; 
    public DictionaryAdapter(IDictionary d) 
    { 
     dictionary = d; 
    } 
    public string GetComponentName() 
    { 
     return TypeDescriptor.GetComponentName(this, true); 
    } 
    public EventDescriptor GetDefaultEvent() 
    { 
     return TypeDescriptor.GetDefaultEvent(this, true); 
    } 
    public string GetClassName() 
    { 
     return TypeDescriptor.GetClassName(this, true); 
    } 
    public EventDescriptorCollection GetEvents(Attribute[] attributes) 
    { 
     return TypeDescriptor.GetEvents(this, attributes, true); 
    } 
    EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents() 
    { 
     return TypeDescriptor.GetEvents(this, true); 
    } 
    public TypeConverter GetConverter() 
    { 
     return TypeDescriptor.GetConverter(this, true); 
    } 

    public object GetPropertyOwner(PropertyDescriptor pd) 
    { 
     return dictionary; 
    } 
    public AttributeCollection GetAttributes() 
    { 
     return TypeDescriptor.GetAttributes(this, true); 
    } 
    public object GetEditor(Type editorBaseType) 
    { 
     return TypeDescriptor.GetEditor(this, editorBaseType, true); 
    } 
    public PropertyDescriptor GetDefaultProperty() 
    { 
     return null; 
    } 
    PropertyDescriptorCollection 
     System.ComponentModel.ICustomTypeDescriptor.GetProperties() 
    { 
     return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[] { }); 
    } 
    public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     ArrayList properties = new ArrayList(); 
     foreach (DictionaryEntry e in dictionary) 
     { 
      properties.Add(new DictionaryPropertyDescriptor(dictionary, 
       e.Key.ToString())); 
     } 
     PropertyDescriptor[] props = 
      (PropertyDescriptor[])properties.ToArray(typeof(PropertyDescriptor)); 
     return new PropertyDescriptorCollection(props); 
    } 
} 
public class DictionaryPropertyDescriptor : PropertyDescriptor 
{ 
    IDictionary dictionary; 
    string key; 

    internal DictionaryPropertyDescriptor(IDictionary d, string k) 
     : base(k.ToString(), null) 
    { 
     dictionary = d; 
     key = k; 
    } 
    public override Type PropertyType 
    { 
     get { return dictionary[key].GetType(); } 
    } 
    public override void SetValue(object component, object value) 
    { 
     dictionary[key] = value; 
    } 
    public override object GetValue(object component) 
    { 
     return dictionary[key]; 
    } 
    public override bool IsReadOnly 
    { 
     get { return false; } 
    } 
    public override Type ComponentType 
    { 
     get { return null; } 
    } 
    public override bool CanResetValue(object component) 
    { 
     return false; 
    } 
    public override void ResetValue(object component) 
    { 
    } 
    public override bool ShouldSerializeValue(object component) 
    { 
     return false; 
    } 
} 

: 여기

propertyGrid1.SelectedObject = new DictionaryAdapter(dictionary); 

이 구현되어 그럼 당신은 단순히 이런 식으로 사전 편집 할 수 있습니다 옵션 2 - 데이터 테이블 사용

또한 간단한 옵션으로 DictionaryDataTable으로 지정하고 데이터를 편집 할 수 있습니다.

public static class DictionaryExtensions 
{ 
    public static DataTable ToDataTable<T>(this Dictionary<string, T> dictionary) 
    { 
     var dt = new DataTable(); 
     dictionary.Keys.ToList().ForEach(x => dt.Columns.Add(x, typeof(T))); 
     dt.Rows.Add(dictionary.Values.Cast<object>().ToArray()); 
     return dt; 
    } 
    public static void UpdateFromDataTable<T>(this Dictionary<string, T> dictionary, 
     DataTable table) 
    { 
     if (table.Rows.Count == 1) 
      table.Columns.Cast<DataColumn>().ToList().ForEach(x => 
       dictionary[x.ColumnName] = table.Rows[0].Field<T>(x.ColumnName)); 
    } 
} 

을 그리고이 확장 방법이 방법 사용 :

이 작업에 대한 확장 메서드를 만들 수 있습니다

Dictionary<string, int> dictionary; 
public void Form1_Load(object sender, EventArgs e) 
{ 
    dictionary = new Dictionary<string, int>() { { "A", 1 }, { "B", 2 }, { "C", 3 } }; 
    dataGridView1.DataSource = dictionary.ToDataTable(); 
} 
private void button1_Click(object sender, EventArgs e) 
{ 
    dictionary.UpdateFromDataTable(dataGridView1.DataSource as DataTable); 
} 
+0

보다 안정적인 예외 처리를 추가해야 할 수도 있습니다. –

관련 문제