Click here to Skip to main content
13,195,564 members (71,398 online)
Rate this:
 
Please Sign up or sign in to vote.
See more:
Hello, I am working on one assignment using WPF and MongoDB. I need to generate WPF DataGrid(any other control will be fine if it works) at runtime from List of Dictionary<string,string>. This is simple collection Dictionary where each Dictionary has different set of keypairs.

So far i am able to generate columns at runtime from Dictionary<string,string> having highest number of columns. After generating all columns, task is to put data into DataGrid and display.

List of Dictionary<string,string> contains different set of columns in each dictionary when i tried using DataContext and ItemsSource of DataGrid but it generates empty gird.

Please provide your thoughts
Posted 26-Dec-12 3:35am
DevD9196
Updated 29-Jul-17 7:52am
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 1

Hello
I would first of all choose the ObservableCollection instead of the List.
That is because that list inherits the ICollectionChanged interface so that changes in the collection will appear in the UI when binding to the collection form the ItemSource property on the datagrid.

Second, I would not use a Dictionary to hold the data. I would create a class with properties for all the "keys" or "columns", that I create the ObservableCollection of.

When all this is done, I would use the MVVM model (my personal choice) but there are many alternatives. And I would use Binding in the XAML from the ItemSource to a property in the model holding the ObservableCollection of my values. That is a quick and easy way of solving the problem, I think.

Hope it helps!
  Permalink  
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 2

Well obviously
You might need to replace List<Dictionary<string,string>> to more WPF convenient collection ObservableCollection<IList<KeyValueHolder>> Items ,
where KeyValueHolder is siple entity , see:

public class KeyValueHolder
{
 public string Key {get;set;}
 public string Value {get;set;}
} 
.

But one moment to consider, by it's nature ObservableCollection is not Thraed-safe!!

So , in your scenario i think , would be prafarable to implements master-details approach,(you will have 2 datagrids: - first is general, represent number of your dictionaries, and second one is detailed by list of KeyValueHolder)
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 3

Thanks. This is how i resolve it.
table = new DataTable();
            dgSearchResult.Columns.Clear();
            string broker = string.Empty;
            string producttype = string.Empty;
            string currency = string.Empty;
            string productsubtype = string.Empty;
 
            if (cmbProductTypes.SelectedValue != null)
                producttype = cmbProductTypes.SelectedValue.ToString();
            else
                producttype = "";
 
            if (cmbBrokers.SelectedValue != null)
                broker = cmbBrokers.SelectedValue.ToString();
            else
                broker = "";
 
            if (cmbProductSubtype.SelectedValue != null)
                productsubtype = cmbProductSubtype.SelectedValue.ToString();
            else
                productsubtype = "";
 
            if (cmbCurrency.SelectedValue != null)
                currency = cmbCurrency.SelectedValue.ToString();
            else
                currency = "";
//Sample is a list of dict of string string
            List<dictionary><string,string>> sample = Models.RateCards.GetCard(producttype,broker,productsubtype,currency);
 
            foreach (Dictionary<string,> d in sample)
            {
                foreach (string key in d.Keys)
                {
                    Addcolumn(key);
                }
 
            }
 
            foreach (Dictionary<string,> d in sample)
            {
                //Addrow(d);
 
                row = table.NewRow();
                foreach (KeyValuePair<string,> keyValue in d)
                {
                    if (table.Columns.Contains(keyValue.Key))
                    {
                        if (keyValue.Key != "XMLDefinition")
                        {
                            if (keyValue.Value.Contains(","))
                            {
                                //if (keyValue.Key == "Volume Band Rates" || keyValue.Key == "Premium Band Rates")
                                    row[keyValue.Key] = RemoveSpecialCharacters(keyValue.Value.Replace("}, ", "}" + System.Environment.NewLine).Replace(",", ";").Replace("{", "").Replace("}", "").Replace("[", "").Replace("]", "").Replace("''", ""));
                                //else
                                //    row[keyValue.Key] = RemoveSpecialCharacters(keyValue.Value.Replace(",", ";").Replace("{", "").Replace("}", "").Replace("[", "").Replace("]", "").Replace("''", ""));
                            }
                            else
                                row[keyValue.Key] = RemoveSpecialCharacters(keyValue.Value);
                        }
                        else
                            row[keyValue.Key] = keyValue.Value;
                    }
                }
 
                table.Rows.Add(row);
 
            }
            
            dgSearchResult.ItemsSource= table.DefaultView;
            
       }
 
       private static string RemoveSpecialCharacters(string str) 
        {
            StringBuilder sb = new StringBuilder();
            foreach (char c in str) 
            {
                if (c != '"') 
                {
                    sb.Append(c);
                }
            }
            return sb.ToString();
        }
 
        private void Addcolumn(string columnname)
        {
            if (!table.Columns.Contains(columnname))
            {
 
                DataGridTextColumn dgColumn = new DataGridTextColumn();
                dgColumn.Header = columnname;
                dgColumn.Binding = new Binding(string.Format("[{0}]", columnname));
                dgColumn.SortMemberPath = columnname;
                dgColumn.IsReadOnly = true;
                
                dgSearchResult.Columns.Add(dgColumn);
                
                DataColumn dtcolumn = new DataColumn();
                dtcolumn.Caption = columnname;
                dtcolumn.ColumnName = columnname;
                
                table.Columns.Add(dtcolumn);
                if (columnname == "_id" || columnname == "XMLDefinition")
                    dgColumn.Visibility = Visibility.Hidden;
                    
            }
        }</dictionary>
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 4

This is what i use to convert a dictionary-list to a datatable(credit to someone on StackOverflow) to which a datagrid can bind.
N.B if T is not a value-type then you will need to specify the property (of interest).

   public static DataTable ToDataTable<T>(string tableName, Dictionary<string, IEnumerable<T>> dictionary, string property="") 
        {
            Type myType = null;
            DataTable dataTable = new DataTable(tableName);
            DataRow row;
            System.Reflection.PropertyInfo myPropInfo = null;
            bool isValueType = typeof(T).IsValueType;
            if (!isValueType)
            {
                myType = typeof(T);
                myPropInfo = myType.GetProperty(property);
 
            }
 
            int length = 0;
            int i;
            List<System.Collections.IEnumerator> Enumerators = new List<System.Collections.IEnumerator>();
 
            var t = isValueType ? typeof(T) : myPropInfo.PropertyType;
 
            foreach (KeyValuePair<string, IEnumerable<T>> pair in dictionary)
            {
 
                var x = new DataColumn(pair.Key, t);
 
                dataTable.Columns.Add(x);
 

                Enumerators.Add(pair.Value.GetEnumerator());
                length++;
 
            }
 

 
            while (length > 0)
            {
                row = dataTable.NewRow();
            
                i = 0;
                foreach (KeyValuePair<string, IEnumerable<T>> pair in dictionary)
                {
 
                    if (Enumerators[i].MoveNext())
                        row[i] = isValueType ? Enumerators[i].Current : myPropInfo.GetValue(Enumerators[i].Current, null);
 
                    else
                        length--;
 
                    i++;
 
                }
                dataTable.Rows.Add(row);
            }
 
            return dataTable;
        }
  Permalink  
v2
Comments
Graeme_Grant 29-Jul-17 16:01pm
   
This is a 5-year-old question. Do you really think that he is still waiting for an answer? Please don't answer tombstoned questions, only current outstanding ones.
Member 12805636 9-Oct-17 5:56am
   
No I don't think so; but wpf hasn't change too much in 5 years. And this question is still relevant today. So it was never meant for the person who asked the question but for anyone else who like me stumbled into this corner of the web. The problem with it is that it misses out some details/ is wrong:

This converts a dictionary to a datatable to which you can bind a datagrid. Directly binding a dictionary isn't feasible in this scenario.






This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


Advertise | Privacy |
Web02 | 2.8.171019.1 | Last Updated 9 Oct 2017
Copyright © CodeProject, 1999-2017
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100