I have the following code as part of a WPF I am creating:
Dictionary<string, string[]> storeDictionary = new Dictionary<string, string[]>();
private void populateDropbox()
{
storeDropDown.DataSource = new BindingSource(storeDictionary, null);
storeDropDown.DisplayMember = "Key";
storeDropDown.ValueMember = "Value";
storeDropDown.SelectedValue = 0;
}
Note: storeDropDown is name of the combobox.
How would I get storeDropdown.Valuemember to be the first element of the string[]?
Please bare in mind this is my first program and c# is my first programming language.
If you need more info let me know, thanks.
You say you are doing WPF but the ComboBox you are using comes from winforms.
So what are you actually working on?
Assuming you are using Winforms (the ComboBox of your example) here is my solution:
1 - Create a class to encapsulate your array of string and override the ToString() method
internal class CustomArrayOfStrings
{
public string[] _strings;
public override ToString()
{
return _strings[0];
}
}
Now your dictionary looks like something like this:
Dictionary<string, CustomArrayOfStrings> storeDictionary = new Dictionary<string, CustomArrayOfStrings>();
2- Then, to display the first element in your ComboBox you change
storeDropDown.DisplayMember = "Key";
to
storeDropDown.DisplayMember = "Value";
This will call the ToString methode of your Value wich is a CustomArrayOfStrings.
3 - If you want to manipulate the selected first element of your array, you can do it this way:
CustomArrayOfStrings selected = storeDropDown.SelectedValue as CustomArrayOfStrings;
string firstValue = selected._strings[0];
Related
At the top of the form
Dictionary<string, string> FileList = new Dictionary<string, string>();
In the constructor
public Form1()
{
InitializeComponent();
if (System.IO.File.Exists(Path.Combine(path, "test.txt")))
{
string g = System.IO.File.ReadAllText(Path.Combine(path, "test.txt"));
FileList = JsonConvert.DeserializeObject<Dictionary<string, string>>(g);
listBox1.DataSource = FileList.ToList();
}
instead making :
listBox1.DataSource = FileList.ToList();
and then in the listBox i will see for example "hello", "d:\test\test1.txt"
I want that in the listBox there will be only : "hello"
I don't want to change the FileList but to change what will be adding from the FileList to the listBox and that is only the left side.
another problem might be with the listBox selected index :
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var item = ((ListBox)sender).SelectedItem;
var itemCast = (KeyValuePair<string, string>)item;
pictureBox1.Image = System.Drawing.Image.FromFile(itemCast.Value);
}
in one hand i don't want to see in the listBox the right side the values in the other hand i want the selected index event to be working.
A dictionary maps keys to values. What you call "left part/side" is actually the key, and the other element is the value.
C# Dictionary has a property: Keys which returns only the keys in the dictionary (e.g. your "hello" string).
Therefore you can use:
listBox1.DataSource = FileList.Keys.ToList();
Note that if you ever need only the values (e.g. "d:\test\test1.txt" etc.), Dictionary has a similar property: Values.
I'm guessing that, when the user selects a key, you're going to want to get the corresponding value. In that case, rather than just binding the keys, bind the whole Dictionary:
myListBox.DisplayMember = "Key"
myListBox.ValueMember = "Value"
myListBox.DataSource = myDictionary.ToArray()
Each item is a KeyValuePair, which has Key and Value properties. The code above will display the keys and then, when the user selects an item, you can get the corresponding value from the SelectedValue property.
Note that data-binding like this requires an IList, while the Dictionary only implements ICollection. For that reason, you need to call ToArray or ToList to create an IList for binding.
I'm using Visual Studio 2010 express and working on a C# WinForms application.
My form has a ListBox object (listData) which has its DataSource set to use a Key-Value paired Dictionary object (dictionary).
This is the Dictionary and how it is assigned as a DataSource to listData-
Dictionary<string, uint> dictionary = new Dictionary<string, uint>();`
listData.DataSource = new BindingSource(dictionary, null);
listData.DisplayMember = "Key";
listData.ValueMember = "Value";
And when debugging I see that the "Value" is being assigned correctly and is clearly a number. Yet when I try to accept the same "Value" into a uint lastSelectedIndex, I get this cast error-
What am I doing wrong here?
This actually worked for me:
lastSelectedIndex = ((KeyValuePair<string, uint>)listData.SelectedItem).Value;
You should change this line.
listData.DataSource = new BindingSource(dictionary, null);
to
listData.DataSource = dictionary;
The BindingSource constructor requires two parameters. first one is for data source and second one for DataMember (ValueMember as we can say). You have specified null value into second parameter that's why BindingSource has taken whole KeyValuePair object as a DataMember.
I don't think that you need to create object of BindingSource class to bind the Dictionary class. but, if you still want to use then you should also specify the DataMember in second parameter.
listData.DataSource = new BindingSource(dictionary, "Value");
But, I don't know whether it will work or not. i haven't tried like this before.
The another approach is to convert the SelectedValue into KeyValuePair object and get the Value from it.
uint lastSelectedIndex = ((KeyValuePair<string, uint>)listData.SelectedValue).Value
You are trying to cast KeyValuePair object into uint. So, it cannot be convertable. You have to convert it into KeyValuePair type first then get the value from Value property of that object.
I would like to suggest you to create another class where the class is having two properties
public class MyDataClass
{
public uint Value{ get; set;}
public string Display{get;set;}
public MyDataClass(string display, uint val)
{
Display = display;
Value = val;
}
public override string ToString()
{
return this.Display;
}
}
The create a List<MyDataClass> object and fill the data into it.
Now you can assig that List object directly into that List control.
List<MyDataClass> lstItems = new List<MyDataClass>();
lstItems.Add(new MyDataClass("Item 1", 1));
lstItems.Add(new MyDataClass("Item 2", 2));
lstItems.Add(new MyDataClass("Item 3", 3));
listData.DataSource = lstItems;
listData.DisplayMember = "Display";
listData.ValueMember = "Value";
The reason for this issue is the order you have used to assign the DataSource and the ListBox' ValueMember property. If you assign the DataSource as last step it works:
Dictionary<string, uint> dictionary = new Dictionary<string, uint>();
dictionary.Add("1", 1);
dictionary.Add("2", 2);
dictionary.Add("3", 3);
listData.DisplayMember = "Key";
listData.ValueMember = "Value";
var bs = new BindingSource();
bs.DataSource = dictionary;
listData.DataSource = bs; // as last step
The ListBox' SelectedIndexChanged event will be triggered as soon as you assign the DataSource. Since you haven't specified the ValueMember at that time you get the InvalidCastException.
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
Basically I need to populate a listBox's .Text value with a string and its .Value value with an int.
By doing this:
lbUsers.DataSource = new UserManagerBO().GetGlobalUserList();
lbUsers.DataBind();
This assigns a string to both .Value and .Text.
Now I know GetGlobalUserList() returns a string[] which is why I'm getting the behaviour above, so how to go about returning the int values along with the string ones? Maybe go 2D array? And then how to bind those results to the listbox?
Option 1
Let that method return string[] and for value pick SelectedIndex.
Option 2
Create a custom class as Damith answers.
Option 3
A Dictionary<int, string> will suffice.
Dictionary Keys for ListBox Value and Dictionary Values for ListBox Text.
Say this is the dictionary returned by your method
//Adding key value pair to the dictionary
Dictionary<int, string> dStudent = new Dictionary<int, string>();
dStudent.Add(0, "Eena");
dStudent.Add(1, "Meena");
dStudent.Add(2, "Deeka");
dStudent.Add(3, "Tom");
dStudent.Add(4, "Dick");
dStudent.Add(5, "Harry");
dStudent.Add(6, "Yamla");
dStudent.Add(7, "Pagla");
dStudent.Add(8, "Dewana");
dStudent.Add(9, "Guru");
dStudent.Add(10, "Sholay");
Step 2:
Now it's time to bind a Dictionary pair with your listbox. The following code binds to listbox.
//binding to the list
lst.DataTextField = "Value";
lst.DataValueField = "Key";
lst.DataSource = dStudent;
lst.DataBind();
Create custom class with user properties. this can be re used when you deal with Global Users
public class CustomClass()
{
public int ID { get; set; }
public int Name { get; set; }
}
return collection of CustomClass objects from GetGlobalUserList(), you need to change the signature and logic of GetGlobalUserList method. Ones you done that,
lbUsers.DataSource = new UserManagerBO().GetGlobalUserList();
set DataTextField and DataValueField of your listbox
lbUsers.DataTextField = "Name";
lbUsers.DataValueField = "ID";
lbUsers.DataBind();
I'm binding a Dictionary to a drop down list.
Say for example I have the following items in dictionary:
{"Test1", 123}, {"Test2", 321}
I'd like the drop down text to take the following format:
Test1 - Count: 123
Test2 - Count: 321
I was going along the following path with no luck:
MyDropDown.DataTextFormatString = string.Format("{0} - Count: {1}", Key, Value);
Thank you :)
You could create a projection view by using LINQ on your dictionary and create an anonymous type to hold your custom formatting.
Dictionary<string, int> values = new Dictionary<string, int>();
values.Add("First", 321);
values.Add("Second", 456);
values.Add("Third", 908);
var displayView = from display in values
select new { DisplayText = display.Key + " Count: " + display.Value };
DropDownList1.DataSource = displayView;
DropDownList1.DataTextField = "DisplayText";
DropDownList1.DataBind();
I don't think that the DropDownList does support DataTextFormatString s that concat a String like you want to do it. As far as I know, you can only use format strings for numbers and dates. (For examples see here: http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listcontrol.datatextformatstring.aspx)
You can either do it the way ChristiaanV proposes (anonymous type), or you use your own POCO class (class only containing properties).
Be aware that using anonymous types have a limited scope. You can't usem them in a BusinessLayer-Assembly and have the GUI-Assembly use the result, because the ability of returning an anonymous type from a method are very limited.
I'd suggest you do something like this:
public class MyPOCO
{
public int MyPrimaryKey {get;set;}
public String DisplayString {get;set;}
}
Create a List<MyPOCO> in your code and bind it to the DataSource property.
Set the DataValueField to MyPrimaryKey and the DataTextField to DisplayString
If you are having problems with your databinding on postbacks, you can do the following:
Create a method that returns a List<MyPOCO>
Create a ObjectDataSource and use the wizard to select the methods you created in 1.
Assign the ID of the ObjectDataSource to the DataSourceID of the DropDownList.
You cannot use string.Format in
DataTextFormatString
Try the following code.
Dictionary<string, int> s = new Dictionary<string, int>();
s.Add("Test1", 123);
s.Add("Test2", 321);
foreach(KeyValuePair<string,int> temp in s)
{
DropDownList1.Items.Add(new ListItem(string.Format("{0} - Count: {1}", temp.Key, temp.Value),temp.Value.ToString()));
}