0

I have an IDictionary which holds an ever changing list of my class and I want to display the collection in a winforms UI probably using DataGridView or another control. I plan to have timer that refreshes the table every 1 to 2 seconds and a pause button. when any given row is clicked I need to be able to get the class from the dictionary or return the first field which be the key in the IDictionary.

So I create the IDictionary thus:

public static IDictionary<string, AClass> aList = new Dictionary<string, AClass>();

AClass is a simple collection of strings:

public class AClass
{
    public string data1{ get; set; }
    public string data2{ get; set; }
}

I add the AClass to the IDictionary thus:

 if (!MainForm.aircraftList.ContainsKey(strMyData))
        {
            MainForm.aList[strMyData] = new AClass{ data1= strMyData};
        }

How can I create the table with all the columns from AClass which are around 12 and rows from the IDictionary aList of which there is a variable number hovering around 100.

mm8
  • 163,881
  • 10
  • 57
  • 88
Adrian
  • 1,089
  • 24
  • 51
  • I am guessing you want to display this data into a `DataGridView`? – JohnG Feb 12 '17 at 16:55
  • Yes that would be good, but if there is a better control i'm not tied to using it. – Adrian Feb 12 '17 at 16:57
  • It appears a `DataGridView` will work to display your data. If you are using a class, then I would recommend either a simple `List` or better yet a `DataTable` to hold the data then set the `DataGridView`'s `DataSource` to this `List/DataTable`. If you use a `Dictionary` for this, you may have to go through some extra steps to get the data to display properly. – JohnG Feb 12 '17 at 17:03
  • Do you just want to display the properties of AClass, or do you also want to display the dictionary key for each AClass? – TnTinMn Feb 12 '17 at 17:12
  • just the properties is fine – Adrian Feb 12 '17 at 17:23

2 Answers2

1

To possibly help you get started, below is code that uses a DataGridView to display data using a DataTable; a List<AClass> objects and also using a Dictionary<string, AClass>. As I said using a dictionary, you will have to do some extra steps to get the AClass Value from the dictionary. These extra steps indicate that the Dictionary is not necessarily the best data structure to use as a DataSource if there a multiple variables in your class.

The code below uses a DataGridView and four (4) buttons. There are buttons to display data into the DataGridView using a DataTable; a List<AClass> (added a key), and a Dictionary<string, AClass> and finally a button to clear the DataGridView

Hope this helps.

public Dictionary<string, AClass> DGVDictionary;
public DataTable DGVTable;
public List<AClass> DGVList;

public Form1() {
  InitializeComponent();
}

private Dictionary<string, AClass> GetDictionary() {
  Dictionary<string, AClass> dictionary = new Dictionary<string, AClass>();
  for (int key = 0; key < 15; key++) {
    AClass ac = new AClass();
    ac.data1 = "data1" + key;
    ac.data2 = "data2" + key;
    dictionary.Add(key.ToString(), ac);
  }
  return dictionary;
}

private void CreateTable() {
  DGVTable = new DataTable();
  DGVTable.Columns.Add("key", typeof(int));
  DGVTable.Columns.Add("data1", typeof(string));
  DGVTable.Columns.Add("data2", typeof(string));
}

private void FillDataTable() {
  for (int key = 0; key < 15; key++) {
    AClass ac = new AClass();
    ac.data1 = "data1" + key;
    ac.data2 = "data2" + key;
    DGVTable.Rows.Add(key, ac.data1, ac.data2);
  }
}

private List<AClass> FillList() {
  List<AClass> list = new List<AClass>();
  for (int key = 0; key < 15; key++) {
    AClass ac = new AClass();
    ac.key = key;
    ac.data1 = "data1" + key;
    ac.data2 = "data2" + key;
    list.Add(ac);
  }
  return list;
}

 private void buttonDataTable_Click(object sender, EventArgs e) {
  CreateTable();
  FillDataTable();
  dataGridView1.DataSource = DGVTable;
  MessageBox.Show("DGV with a DataTable");
}

private void buttonList_Click(object sender, EventArgs e) {
  DGVList = FillList();
  dataGridView1.DataSource = DGVList;
  MessageBox.Show("DGV with a List<AClass>");
}

private void buttonDictionary_Click(object sender, EventArgs e) {
  DGVDictionary = GetDictionary();
  dataGridView1.DataSource = DGVDictionary.ToList();
  MessageBox.Show("DGV with a Dictionat<string, AClass>");
}

private void buttonClear_Click(object sender, EventArgs e) {
  dataGridView1.DataSource = null;
}
JohnG
  • 9,259
  • 2
  • 20
  • 29
  • Thank you John I will play with this and try see how i can use this approach too. – Adrian Feb 12 '17 at 20:39
  • in the function buttonDataTable_Click is there a way of making it show the key and one of the values in the class say data2? – Adrian Feb 12 '17 at 21:15
  • The `buttonDataTable_Click` event is made to specifically get and fill the `DatGridView` you could easily change this to look for what ever key value pair you want. – JohnG Feb 15 '17 at 07:43
0

Since you are using an IDictionary, the default binding mechanism will not be able to retrieve the individual entries nor the properties on the class AClass. You can create a custom BindingSource to handle these tasks.

The primary responsibility of custom BingSource is to supply a collection of ProperyDescriptors for the AClass type. These are retrieved using the TypeDescriptor.GetProperties Method. The BindingSource also needs to access the underlying DataSource items by index; this is handled in the indexer of the BindingSource.

To use this BindingSource, create an instance of it passing your IDictionary instance and then assign this BindingSource to the DataGridView's DataSource property.

internal class myBindingSource : BindingSource
    {
    private IDictionary<string, AClass> source;
    private System.ComponentModel.PropertyDescriptorCollection props;

    public myBindingSource(IDictionary<string, AClass> source)
        {
        this.source = source;
        props = System.ComponentModel.TypeDescriptor.GetProperties(typeof(AClass));
        this.DataSource = source;
        }

    public override System.ComponentModel.PropertyDescriptorCollection GetItemProperties(System.ComponentModel.PropertyDescriptor[] listAccessors)
        {
        return props;
        }

    public override object this[int index]
        {
        get {return this.source.Values.ElementAtOrDefault(index);}
        set {}
        }

    public override bool AllowNew
        {
        get { return false; }
        set{}
        }

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

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

    public override int Count
        {
        get {return ((this.source == null) ? -1 : this.source.Count);}
        }
    }

Edit: I have added an override of the Count property to the code to allow the the BindingSource.ResetBindings Method to work properly when called to force the bound control to re-read the values from the BindingSource. I have also updated the indexer code.

If you modify the custom BindingSource's underlying DataSource after assigning it as the DataGridView's DataSource, you will need to call the BindingSource.ResetBindings method for those changes to be reflected in the grid.

For Example:

    private IDictionary<string, AClass> aList;
    private myBindingSource bs;

    public Form1()
        {
        InitializeComponent();
        aList = new Dictionary<string, AClass>();

        bs = new myBindingSource(aList);
        dgv.DataSource = bs;

        aList.Add("1", new AClass());
        aList.Add("2", new AClass { data1 = "AA", data2 = "BB" });
        bs.ResetBindings(false);
        }
TnTinMn
  • 11,522
  • 3
  • 18
  • 39
  • thank you for this, a lot of it is beyond me, however i have added it and it does add all the names across the top of the datagrdiview . I create it before filling the list as the form loads. how do i make it up date the data following each time i add or remove items to the dictionary? – Adrian Feb 12 '17 at 20:37
  • actually I can't get it to show the data only the properties names on a header row not the data in each row below it. – Adrian Feb 12 '17 at 20:50
  • @Adrian, I updated my answer and provided a short example. The code also has some minor changes to handle what I think you want to do. – TnTinMn Feb 12 '17 at 21:56
  • thank you for help and this would seem a good solution however i not get it to show the data so went with the other answer. – Adrian Feb 16 '17 at 14:25