Binding Dictionary To Datagridview - c#

I wanted to bind a dictionary to a datagridview. Unfortunately Dictionary does not implement the required interface, so instead a created a List>.
Essentially I want this to be bound to a datagridview with datagridviewcomboboxcolumns. With column 1 holding the Key and column 2 holding the value.
I've tried loads of variations, but I can't seem to get this right. I've tried binding to the columns, to individual cells, and to the datagridview itself. Does anybody know how to do this?
EDIT: To clarify it's not binding to the object that's the problem. It seems to binding to the List okay, for example, if I have 4 items in the List, then 4 rows are added, however the values are blank. This is the example code:
additionalMetadata1.dataGridView1.DataSource = animal.AdditionalMetaData;
foreach (DataGridViewRow row in additionalMetadata1.dataGridView1.Rows)
{
DataGridViewCustomComboCell cell = row.Cells[0] as DataGridViewCustomComboCell;
cell.DataSource = animal.AdditionalMetaData;
((DataGridViewCustomComboColumn)additionalMetadata1.dataGridView1.Columns[0]).DisplayMember = "Key";
((DataGridViewCustomComboColumn)additionalMetadata1.dataGridView1.Columns[0]).ValueMember = "Key";
((DataGridViewCustomComboColumn)additionalMetadata1.dataGridView1.Columns[0]).DataPropertyName = "Key";
}
Thanks.

You could use your Dictionary with the following Linq:
dataGridView.DataSource = (from d in dictionary
orderby d.Value
select new
{
d.Key,
d.Value
}).ToList();
This will create an anonymous object that will hold your Key and Value as properties. Be aware that the dictionary is by default not in a particular order.

Try like this
dataGridView1.ColumnCount = 2;
foreach (KeyValuePair<string, string> kvp in dict) {
string[] arow = new string[] { kvp.Key, kvp.Value };
dataGridView1.Rows.Add(arow);
}
or
dataGridView1.DataSource = dict.ToArray();
or
dataGridView1.DataSource = dict.Select((kv => new {
myKeys = kv.Key,
myValues = kv.Value
})).ToArray();

Related

WinForms ComboBox

I'm trying to mark one of the combobox items as selected.
So I am building my combobox like this:
var drop = new Dictionary<int, string>();
while (RegReader.Read())
{
drop.Add(Convert.ToInt32(RegReader["intRulesID"]), RegReader["txtName"].ToString());
}
RegRuleDrop.DataSource = new BindingSource(drop, null);
RegRuleDrop.DisplayMember = "Value";
RegRuleDrop.ValueMember = "Key";
Now, one of the items within the RegRuleDrop should be pre selected based on a value from a reader above this code.
Now, the problem is that I need to select value based on the actual ListItem VALUE and not TEXT.
So as an example
drop.Add(1, "Test");
drop.Add(2, "Test2");
drop.Add(3, "Test3");
I need to find the index using 1,2 or 3 not Test, Test2 or Test3
Any ideas?
When you have the DataSource set to a BindingSource the only action needed to select an item given a value belonging to the ValueMember property is
drop.Add(1, "Test1");
drop.Add(2, "Test2");
drop.Add(99, "Test99");
drop.Add(3, "Test3");
.....
RegRuleDrop.SelectedValue = 99

How can I change my current selected item by either the key or value of my datasource?

I have a Dictionary<uint, string> and a ComboBox using the style DropDownList, where I bind this dictionary, like:
comboBox1.DataSource = new BindingSource(myDic, null);
comboBox1.DisplayMember = "Value";
comboBox1.ValueMember = "Key";
Now I would like to be able to select an arbitrary item of my dictionary with a button click, so given the bound dictionary items:
Dictionary<uint, string> myDic = new Dictionary<uint, string>()
{
{ 270, "Name1" },
{ 1037, "Name2" },
{ 1515, "Name3" },
};
I have tried:
comboBox1.SelectedItem = myDic[270];
comboBox1.SelectedText = myDic[270];
comboBox1.SelectedValue = myDic[270];
comboBox1.SelectedItem = 270;
comboBox1.SelectedValue = 270;
But none of the above changed the selected item.
How can I change my current selected item by either the key or value of my datasource?
You can do it with a little extension method I found here
Just put this into an extension class.
public static KeyValuePair<TKey, TValue> GetEntry<TKey, TValue>
(this IDictionary<TKey, TValue> dictionary,
TKey key)
{
return new KeyValuePair<TKey, TValue>(key, dictionary[key]);
}
And then you can just set your item like this
comboBox1.SelectedItem = myDic.GetEntry<uint,string>(1515);
The key to this problem is that you have to set the KeyValuePair (and not just the uint or string value/key).
Hope this helps!
This works sufficiently. Not sure about the performance on very large lists, but you probably don't want a huge ComboBox list either.
foreach (var item in myDic)
comboBox1.Items.Add(item.Value); // Populate the ComboBox by manually adding instead of binding
comboBox1.SelectedIndex = comboBox1.Items.IndexOf(myDic[1037]);
The clear issue with this code is the dismissal of the DataSource Binding, which may or may not be okay with you. Perhaps someone else will provide a better answer.
Yesterday looking for, I happened to inquire driving the DataSource, it casts it to BindingSource and discovered that a property "Current" which determines that KeyPar is selected internally from the link. So change the values to test and Bingo !
Dictionary<int,string> diccionario=new Dictionary<int,string>();
diccionario.Add(1,"Bella");
diccionario.Add(2,"Bestia");
this.comboList.DisplayMember = "Value";
this.comboList.ValueMember = "Key";
this.comboList.DataSource = new BindingSource(diccionario, null);
((BindingSource)this.comboList.DataSource).Position=0; // select init
///////Method's change ///////
((BindingSource)this.comboList.DataSource).Position =Convert.ToInt32(value);

DevExpress LookUp repository item binded to dictionary set members

I have created a dictionary with an int key and a string value. I managed to set the dictionary as the datasource of my LookUp field. The lookup field is a repository item in a devexpress GridControl. The dictionary values are shown in my LookUp but I want to set the display and value member (and the caption) and don't know how to do this. Below you can see the current situation.
The dictionary code:
Dictionary<int, string> IncIncControls = new Dictionary<int,string>()
{
{ 1, "IncIncidentId"},
{ 2, "IncIncidentType"},
{ 3, "IncIncidentPriority"}
};
And the code to set the LookUp source
pageFieldLookUp.DataSource = (from d in IncIncControls
orderby d.Value
select new
{
d.Key,
d.Value
}).ToList();
How to modify the code to set lookup source in a way that I can set the display member/value member and caption. Or is there another (better) way to do this?
You can simply use RepositoryItemLookUpEditBase.DisplayMember and RepositoryItemLookUpEditBase.ValueMember properties for set display and value members, and use RepositoryItemLookUpEdit.Columns property to set captions:
pageFieldLookUp.DataSource = (from d in IncIncControls
orderby d.Value
select new
{
d.Key,
d.Value
}).ToList();
pageFieldLookUp.ValueMember = "Key";
pageFieldLookUp.DisplayMember = "Value";
pageFieldLookUp.PopulateColumns();
pageFieldLookUp.Columns[0].Caption = "Key caption";
pageFieldLookUp.Columns[1].Caption = "Value caption";

How to append to the dictionary?

I have a dictionary defined.
Dictionary<string, string> dataSource;
There is a function defined in such a way that this Dictionary will get filled atleast ones.
dataSource = l2ListText
.Zip(l2ListValue, (lText, lValue) => new { lText, lValue })
.ToDictionary(x => x.lValue, x => x.lText);
l2ListText and l2ListValue are List<String>
This filled in datasource dictionary serves as a datasource for a listbox.
And second time round, it checks if a listbox is empty, and when it is NOT empty, I want to append values to this dataSource and re-assign it as a datasource to the listbox again.
I am finding it difficult to achieve this, please help.
Main problem in your code is that you initialize Dictionary with each call. Thus, you will never achieve adding items, only populating it from l2Lists
This line Dictionary<string, string> dataSource; should be moved at class level to ensure you have same instance for each call to the method.
Modified code is below:
if (dataSource != null && lstbx_confiredLevel2List.Items.Count > 0)
{
dataSource.Add(l2ListValue[0], l2ListText[0]);
}
else {
dataSource = l2ListText .Zip(l2ListValue, (lText, lValue) => new { lText, lValue }) .ToDictionary(x => x.lValue, x => x.lText);
}
lstbx_confiredLevel2List.DataSource = dataSource;
lstbx_confiredLevel2List.DataTextField = "Value";
lstbx_confiredLevel2List.DataValueField = "Key";
lstbx_confiredLevel2List.DataBind();
Without the LINQ .Zip extension, you can also do:
dataSource = new Dictionary<string, string>();
int zipCount = Math.Min(l2ListText.Count, l2ListValue.Count);
for (int idx = 0; idx < zipCount; ++idx)
datasource.Add(l2ListValue[idx], l2ListText[idx]);
The for loop appends to your Dictionary<,>. If you run a similar for loop again, new values will be appended. Note that this will fail if the same "keys" (members from l2ListValue) are added again. If you want, you can overwrite existing members insted:
for (int idx = 0; idx < zipCount; ++idx)
datasource[l2ListValue[idx]] = l2ListText[idx];

ComboBox AutoComplete with Key/Value Pair

I have a ComboBox with the following code:
private void comboBox1_TextChanged(object sender, EventArgs e)
{
using (var service = WebServiceHelper.GetCoreService())
{
string physicianXml = service.SearchPhysicians(SessionInfo.Current.ClientCode, SessionInfo.Current.MachineName,
SessionInfo.Current.Username, comboBox1.Text);
var physicians = PhysicianItemList.FromXml(physicianXml);
AutoCompleteStringCollection autoCompleteStringCollection = new AutoCompleteStringCollection();
foreach (var physician in physicians.Items)
{
autoCompleteStringCollection.Add(physician.LastName + ", " + physician.FirstName);
}
comboBox1.AutoCompleteCustomSource = autoCompleteStringCollection;
comboBox1.Select(comboBox1.Text.Length, 0);
}
}
Basically, a user types the first few characters of a physician's name and it should populate the auto-complete list with the top 100 matching records. It works great, but I need to associate it back to a key (either the PK from the table, or the Physician's NPI number). It seems the AutoCompleteStringCollection doesn't support keys. Can anyone suggest a way of doing this? There are approximately 7 million records in the table, so I don't want to prepopulate the ComboBox.
Thanks
When you build your AutoCompleteStringCollection, build a Dictionary<String, int> for the name, id pairs as well. Then use some event (textbox validation or user submit/save click) to lookup and set the id. You could store the dictionary on the textbox Tag.
Edit
For some reason I thought you were working with a textbox control. Forget about the AutoCompleteStringCollection and just build a Dictionary<String, int>. For the combobox set your autocompletesource to ListItems, set the combobox display name and value and set the datasource to the dictionary.
combobox.DisplayMember = "key";
combobox.ValueMember = "value";
combobox.AutocompleteSource = AutocompleteSource.ListItems;
combobox.DataSource = myDictionary;
However you should only populate the datasource and autocomplete once when the user enters n characters in the combobox, otherwise it gets buggy. I tried to use this for a dynamic autocomplete once (eg the list clears if the user clear the text and retypes), but I had to forget about the combobox and use a hybrid textbox listbox approach much like this user
It looks like your problem is that AutoCompleteStringComplete was made specifically for strings (hence, the name).
You may want to look into the parents (IList, ICollection, IEnumerable) and see if you can homebrew something templated toward a key/value struct.
Too late but maybe someone will use this code :
this.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
this.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
RNProveedor rnProveedor = new RNProveedor();
var listaProveedores = rnProveedor.Buscar();
Dictionary<int, String> dicTemp = new Dictionary<int, string>();
foreach (var entidad in listaProveedores)
{
dicTemp.Add(entidad.ProvNro, entidad.ProNombre);
}
this.DataSource = new BindingSource(dicTemp, null);
this.DisplayMember = "Value";
this.ValueMember = "Key";
And to select the value
public int GetValorDecimal()
{
KeyValuePair<int, string> objeto = (KeyValuePair<int, string>)this.SelectedItem;
return objeto.Key;
}
With this example you won't have any problem with duplicated strings as the examples above

Categories