How to add value into my combobox options in c#? - c#

I have combobox in my windows forms app and I want it to have values on particular options.
Now I can only put an option, and when I choose it - I can get it via
combobox.text
My target is to list filenames in combobox and have paths to them in values.
Example: Text is= "option1" value which it contains is = "value1", how to do it?
I saw a few topics about it, but they are about 2 years old, maybe something changed, cause these solutions were not so friendly : ]
UPDATE
I've got one issue with your solution, Mahmoud Gamal : )
I'm doing it this way:
List<Foo> combo3data = new List<Foo>();
categories = Directory.GetDirectories(#"C:\banners\categories\");
// There are 3 different paths in categories[] array (category1, category2 and 3)
Foo categoryInsert = new Foo();
foreach (string s in categories)
{
categoryInsert.path = s;
categoryInsert.name = s;
combo3data.Add(categoryInsert);
}
comboBox3.DataSource = combo3data;
comboBox3.ValueMember = "path";
comboBox3.DisplayMember = "name";
After that my comboBox3 has 3 available options (correct) but all of them are the same (same as option #1) - why is that?

You are looking for the two properties:
ValueMember.
DisplayMember.
In your case, you have to set the combobox's ValueMember property to value1 and the DisplayMember property to option1.
Update: The following is an exmple of how you can populate the items of a combobox from list of some entity Foo:
public class Foo(){
public string Id { get; set; }
public string Name { get; set; }
}
var ds = new List<Foo>(){
new Foo { Id = "1", Name = "name1" },
new Foo { Id = "2", Name = "name2" },
new Foo { Id = "3", Name = "name3" },
new Foo { Id = "4", Name = "name4" },
};
comboboxName.DataSource = ds;
comboboxName.ValueMember = "Id";
comboboxName.DisplayMember = "Name";
Update2: That's because you are adding the same object each time. In the following block of your code:
Foo categoryInsert = new Foo();
foreach (string s in categories)
{
categoryInsert.path = s;
categoryInsert.name = s;
combo3data.Add(categoryInsert);
}
Each time The foreach iterate over the categories, all what it does, is changing the same object categoryInsert's values path and name not creating a new one. Thus, you end up with the same object added in each iteration to the combo3data. What you need is create a new Foo object inside the foreach itself each time, i.e: move the Foo categoryInsert = new Foo(); inside the foreach loop. Something like:
foreach (string s in categories)
{
Foo categoryInsert = new Foo();
categoryInsert.path = s;
categoryInsert.name = s;
combo3data.Add(categoryInsert);
}

use comboBox.Text to set or get the text associated with this combobox.
for Values use comboBox.ValueMember for the actual value for the items in the ListControl
or you could also store the values in the comboBox.Tag

Related

Implement List of Objects Using Dictionary Key/Value Pair

I am trying to work with Dictionary<> along with List<> for searching purpose. I know, I can do this easily with List<> as follows:
var con = (from c in db.Customers
where c.Status == status
select c).ToList();
But preferred and tried to implement the above with Dictionary<>. My concept (We all know that) is using the key/value will increase the search option performance. This looks simple and stuck a bit. Here what I've tried:
static void Main(string[] args)
{
Dictionary<string, Customer> custDictionary = new Dictionary<string, Customer>(); //Dictionary declared
List<Customer> lst = new List<Customer>(); //List of objects declared
Customer aCustomer = new Customer(); //Customer object created
/**Assign values - Starts**/
aCustomer.CustomerId = 1001;
aCustomer.CustomerName = "John";
aCustomer.Address = "On Earth";
aCustomer.Status = "Active";
aCustomer.CustomerId = 1002;
aCustomer.CustomerName = "James";
aCustomer.Address = "On Earth";
aCustomer.Status = "Inactive";
/**Assign values - Ends**/
custDictionary.Add(aCustomer.Status, aCustomer); //Added to the dictionary with key and value
string status = Console.ReadLine().ToUpper();
if (custDictionary.ContainsKey(status)) //If key found in the dictionary
{
Customer cust = custDictionary[status];
Console.WriteLine(cust.CustomerId + " " + cust.CustomerName); //Outputs the final result - Right now no result found here
}
Console.ReadKey();
}
public class Customer
{
public int CustomerId { get; set; }
public string CustomerName { get; set; }
public string Address { get; set; }
public string Status { get; set; }
}
Unfortunately, the above doesn't return any result. What I am trying is to get customer details by passing status key and again passed Customer object as the value. I am not sure what I am missing here.
One more thing, in real-life projects, we get database results as list. So in this scenario, if Dictionary<> is used, I believe, the database results should be kept as follows:
lst.Add(aCustomer); //As database will have more result or data simply
On the other hand, I believe, the dictionary should look like the below:
Dictionary<string, List<Customer>> custDictionary = new Dictionary<string, List<Customer>>();
My question - Is it a good idea to pass a list of objects in the dictionary for the key/vale pair and I've tried using so. But didn't get the output yet.
Note: This sounds like a novice question and yes, it's. I've tried to search online and still studying it. I apology to ask such a question and would expect some answers if there are any better ways to do the above.
UPDATED
If you want to store them in a list, you can do the following code. To select the items, you can then use Linq, and in this way you don't have the issue of duplicate values in a dictionary:
var lst = new List<Customer>(); //List of objects declared
lst.AddRange(
new List<Customer>() {
new Customer()
{
CustomerId = 1001,
CustomerName = "John",
Address = "On Earth",
Status = "Active"
},
new Customer()
{
CustomerId = 1002,
CustomerName = "James",
Address = "On Earth",
Status = "Inactive"
}
}
);
var status = Console.ReadLine();
var selected = lst.Where(x => x.Status.ToUpper() == status.ToUpper()).ToList();
foreach (var item in selected)
{
Console.WriteLine(item.CustomerId + " " + item.CustomerName);
}
UPDATE 2
If you want to add the above list in a dictionary, you can do as follows:
var custDictionary = new Dictionary<string, List<Customer>>();
// the above code for the list
custDictionary.Add("keyname", lst);
ORIGINAL ANSWER
You are saving one customer only since you are overwriting the first customer with the second one:
Dictionary<string, Customer> custDictionary = new Dictionary<string, Customer>();
List<Customer> lst = new List<Customer>();
// Add first customer
var aCustomer = new Customer()
{
CustomerId = 1001,
CustomerName = "John",
Address = "On Earth",
Status = "Active"
};
custDictionary.Add(aCustomer.Status.ToUpper(), aCustomer);
// Add second customer
var bCustomer = new Customer()
{
CustomerId = 1002,
CustomerName = "James",
Address = "On Earth",
Status = "Inactive"
};
custDictionary.Add(bCustomer.Status.ToUpper(), bCustomer);
Also you need to store the Status as uppercase, since you are checking if the status exist in uppercase:
string status = Console.ReadLine().ToUpper();
if (custDictionary.ContainsKey(status)) //If key found in the dictionary
{
Customer cust = custDictionary[status];
Console.WriteLine(cust.CustomerId + " " + cust.CustomerName); //Outputs the final result - Right now no result found here
}
Console.ReadKey();
If you already has the list and want to create a Dictionary<string, List<Customer>> you can do it with this:
Dictionary<string, List<Customer>> dict =
list.GroupBy(c=>c.Status.ToUpper()).ToDictionary(g => g.Key, g=> g.ToList());
And iterate it:
foreach (var customer in dict[status.ToUpper()])
{
}
But,
I don't see the value in doing so. if you need to get all the customers with a specific status stay with what you have - a simple linq query.
Even if you are adding status as key, there are 2 problems with your code.
You need to create 2 objects to create 2 customers, one by one. You are adding customer only once, and assigning values twice.
Console.ReadLine().ToUpper() - Remove the ToUpper() since you are adding values in mixed case. If you want to do that, initialize dictionary with StringComparer.InvariantCultureIgnoreCase.
This will work for you.
Dictionary<string, Customer> custDictionary = new Dictionary<string, Customer>(StringComparer.InvariantCultureIgnoreCase); //Dictionary declared
List<Customer> lst = new List<Customer>(); //List of objects declared
Customer aCustomer = new Customer(); //Customer object created
/**Assign values - Starts**/
aCustomer.CustomerId = 1001;
aCustomer.CustomerName = "John";
aCustomer.Address = "On Earth";
aCustomer.Status = "Active";
custDictionary.Add(aCustomer.Status, aCustomer); //Added to the dictionary with key and value
Customer bCustomer = new Customer(); //Customer object created
bCustomer.CustomerId = 1002;
bCustomer.CustomerName = "James";
bCustomer.Address = "On Earth";
bCustomer.Status = "Inactive";
custDictionary.Add(bCustomer.Status, bCustomer); //Added to the dictionary with key and value
string status = Console.ReadLine().ToUpper();
if (custDictionary.ContainsKey(status)) //If key found in the dictionary
{
Customer cust = custDictionary[status];
Console.WriteLine(cust.CustomerId + " " + cust.CustomerName); //Outputs the final result - Right now no result found here
}
Console.ReadLine();
First of all your dictionary key should be customerId not status. it will be a good practice to check if dictionary contains the key other wise it will throw the exception already same key is added. so its better to check then perform add or update in the dictionary.
static void Main(string[] args)
{
Dictionary<string, Customer> custDictionary = new Dictionary<string, Customer>(); //Dictionary declared
List<Customer> lst = new List<Customer>(); //List of objects declared
Customer aCustomer = new Customer(); //Customer object created
/**Assign values - Starts**/
aCustomer.CustomerId = 1001;
aCustomer.CustomerName = "John";
aCustomer.Address = "On Earth";
aCustomer.Status = "Active";
if (!custDictionary.ContainsKey(aCustomer.CustomerId))
custDictionary.Add(aCustomer.CustomerId, aCustomer);
else
custDictionary[aCustomer.CustomerId] = aCustomer;
aCustomer.CustomerId = 1002;
aCustomer.CustomerName = "James";
aCustomer.Address = "On Earth";
aCustomer.Status = "Inactive";
/**Assign values - Ends**/
if (!custDictionary.ContainsKey(aCustomer.CustomerId))
custDictionary.Add(aCustomer.CustomerId, aCustomer);
else
custDictionary[aCustomer.CustomerId] = aCustomer;
string status = Console.ReadLine().ToUpper();
if (custDictionary.ContainsKey(aCustomer.CustomerId)) //If key found in the dictionary
{
Customer cust = custDictionary[aCustomer.CustomerId];
Console.WriteLine(cust.CustomerId + " " + cust.CustomerName); //Outputs the final result - Right now no result found here
}
Console.ReadKey();
}
Your are not getting any output because your are converting your input to uppercase while you have insert the keys in pascalcase and in case of C# collections keys are case sensitive. in this way your input does not matched to any key in collection
change your line number : 29 to this code
string status = Console.ReadLine();
and insert "Inactive" from you console this key exist in your collection
so you will desired result..

C# elegant way to assign properties values rather then duplication

i have searched for something similiar in stackoverflow and couldnt find anything which will give me some hint.
i have following code:
DATA val1 = new DATA();
val1.Name = "KeyValue";
val1.Value = "805373069";
DATA val2 = new DATA();
val2.Name = "Tel";
val2.Value = "0123456789";
DATA val3 = new DATA();
val3.Name = "TargetID";
val3.Value = "43301";
DATA val4 = new DATA();
val4.Name = "ServiceLevel";
val4.Value = "Y";
DATA val5 = new DATA();
val5.Name = "TypeId";
val5.Value = "13505";
DATA val6 = new DATA();
val6.Name = "DateTime";
val6.Value = System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt");
DATA val7 = new DATA();
val7.Name = "DbDateTime";
val7.Value = System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt");
and once all the objects are populated i put them in Single array.
i.e. to be used somewhere else
DATA[] array = {val1,val2,val3,val4,val5,val6,val7};
and Proxy class which i cant change is:
public partial class DATA {
private string nameField;
private string valueField;
public string Name {
get {
return this.nameField;
}
set {
this.nameField = value;
this.RaisePropertyChanged("Name");
}
}
public string Value {
get {
return this.valueField;
}
set {
this.valueField = value;
this.RaisePropertyChanged("Value");
}
}
Now what i have tried and failed to make it easier is used Dictionary and also jagged array and multi dimensional array which didnt worked as i hoped.
can someone give me hint of a better solution then having 7 different objects created, as this data is dynamic i have to do this runtime data population.
suggestions please?
You could just declare the objects in-line as part of the array declaration, if all you're trying to do is avoid having the variables:
DATA[] array = {
new DATA { Name = "something", Value = "something else" },
new DATA { Name = "something", Value = "something else" },
new DATA { Name = "something", Value = "something else" },
new DATA { Name = "something", Value = "something else" }
};
Anywhere that you have a variable, you can instead have the operation which created that variable. The order of operations will result in evaluating to the same thing. Where you'd need a variable is where you want to use the same instance of something multiple times, or the same value without having to re-calculate it.
Put all data in a dictionary if you want to make sure names must not be duplicated:
var data = new Dictionary<string, string>();
// fill dictionary:
data.Add("name1", /*value*/);
data.Add("name2", /*value*/);
data.Add("name3", /*value*/);
data.Add("name4", /*value*/);
Then convert it to array:
return data.Select(d => new Data(){ Name = d.Key, Value = d.Value}).ToArray();
Make sure you have included using System.Linq in top.
UPDATE:
As #LukeH suggested, You can simply use collection initializer like this:
var data = new Data[]
{
new Data(){ Name = "Sylvester", Value = /*value*/ },
new Data(){ Name = "Whiskers", Value = /*value*/ },
new Data(){ Name = "Sasha", Value = /*value*/ }
};
Which doesn't prevent duplicate names for Data type instances.
You can create extension method something like this to overcome the problem of assign properties values rather then duplication,
static class Extensions
{
public static void AddDataObject(this List<DATA> dataList, params string[] values)
{
dataList.Add(new DATA() { Name = values[0], Value = values[1] });
}
}
and passing that values as per given below,
List<DATA> dataList = new List<DATA>();
dataList.AddDataObject("KeyValue", "805373069");
dataList.AddDataObject("Tel", "0123456789");
Here in above example I used List instead of array, you can change according to your requirements
You could initialize an anonymous object and then convert to an array of data like this:
var data = new {
KeyValue="805373069",
Tel="0123456789",
TargetID="43301",
ServiceLevel="Y",
TypeId="13505",
DateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt"),
DbDateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt")
};
var array = data.GetType()
.GetProperties()
.Select(x=>new DATA{Name=x.Name,Value=(string)x.GetValue(data)})
.ToArray();
You could also do it like this:
var data = new {
KeyValue="805373069",
Tel="0123456789",
TargetID="43301",
ServiceLevel="Y",
TypeId="13505",
DateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt"),
DbDateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt")
};
var array=System.Web.Mvc.HtmlHelper.AnonymousObjectToHtmlAttributes(data)
.Select(x=>new DATA {Name=x.Key,Value=(string)x.Value})
.ToArray();
If you need to take an array of data and convert it back into a class object (not anonymous), you can do the first method, just in reverse as well. Or put extension methods on it to convert from/to your data array.
static class Extensions
{
public static DATA[] ToDataArray(this object data)
{
return data.GetType()
.GetProperties()
.Select(x=>new DATA{Name=x.Name,Value=(string)x.GetValue(data)})
.ToArray();
}
}
var data = new {
KeyValue="805373069",
Tel="0123456789",
TargetID="43301",
ServiceLevel="Y",
TypeId="13505",
DateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt"),
DbDateTime=System.DateTime.Now.ToString("ddMMyyyyHHmmssffftt")
};
var array=data.ToDataArray();
However, David's answer is better.

How to select multiple column from data base by getting column from user in .net

I have an object in my database, i.e. with 10 attributes.
Now I want to let the user select some of them (1 or 2 up to 10 of them) and then according by user's selection I make a list of object with the attributes selected by user
the scenario that I think about is this:
A page with check boxes that shows the attributes(columns) of that abject then user selects each of them he needs.
But here is my problem, how to make the selected check boxes run as query?
For example user selected col 1 , col 2, col 6 , col 10, how can I write a query responsible for user selection?
Example I wanna the meaningful phrase of this:
var file2 = file.Select(f => new { "attributes selected by user" }).OrderBy(what user wants)
they System.Linq.Dynamic library on Nuget is a way to go
[TestMethod]
public void StringyAndDangerous()
{
var fakePersonDbSet = new List<Person> { new Person() { FirstName = "Some", LastName = "Guy" } }.AsQueryable();
var attributes = new string[] { "FirstName", "LastName" };
var selectedFields = String.Join(",", attributes);
var exprssion = string.Format("new ({0})", selectedFields);
var result = fakePersonDbSet.Select(exprssion, attributes).Cast<dynamic>().First();
}
but you loose type safety and compile time checking. You might be better taking another approach
[TestMethod]
public void SlowerButSafer()
{
var fakePersonDbSet = new List<Person> { new Person() { FirstName = "Some", LastName = "Guy" } }.AsQueryable();
var attributes = new string[] { "FirstName", "LastName" };
var personPropertylist = CovertToKeyValuePair(fakePersonDbSet.First())
.Where(c=> attributes.Contains(c.Key))
.ToArray();
}
private IEnumerable<KeyValuePair<string, object>> CovertToKeyValuePair<T>(T #object)
{
var result = new List<KeyValuePair<string, object>>();
var properties = typeof (T).GetProperties();
foreach (var property in properties)
{
result.Add(new KeyValuePair<string, object>(property.Name, property.GetValue(#object, null)));
}
return result;
}
you'll take a performance hit both for pulling fields from the database that you don't need and for using reflection but the code will be less error prone and you won't end up with errors for trying to select columns that don't exist.
Use DynamicLinq. (link)
Extension methods:
public static T GetValue<T>(this DynamicClass dynamicObject, string propName)
{
if (dynamicObject == null)
{
throw new ArgumentNullException("dynamicObject");
}
var type = dynamicObject.GetType();
var props = type.GetProperties(BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.FlattenHierarchy);
var prop = props.FirstOrDefault(property => property.Name == propName);
if (prop == null)
{
throw new InvalidOperationException("Specified property doesn't exist.");
}
return (T)prop.GetValue(dynamicObject, null);
}
public static string ToDynamicSelector(this IList<string> propNames)
{
if (!propNames.Any())
throw new ArgumentException("You need supply at least one property");
return string.Format("new({0})", string.Join(",", propNames));
}
Usage:
using System.Linq.Dynamic;
// ..
var columns = new[] { "col1", "col2", etc };
var result = context.Files.OrderBy(file => file.Id)
.Select(columns.ToDynamicSelector())
.Cast<DynamicClass>.ToList();
Result will be the collecion of DynamiClass instances wchich columns will contain selected properties.
To get single property from DynamicClass:
var columnValue = result.First().GetValue<string>("col1");
If you want to get values from IEnumerable:
var list = new List<File> { File1, File2, etc.. };
var result = list.AsQueryable().Select( /* the same as above */);

Set value to ComboBoxCell in DataGridView

I want to set a value for a cell that is actually a comboboxcell. I done it for my another project but now the same way, doesnt work!!
here is my code
//dgExcel is my datagridview
var cmb = (DataGridViewComboBoxColumn)dgExcel.Columns[1];
cmb.DataSource = sucTurleri; //its a list
cmb.DisplayMember = "SucTuru";
cmb.ValueMember = "Id";
and this code is adding row to the grid
var Konumlar = ExcelYardimcisi.KonumlariExceldenAl(dg.FileName);
foreach (var konum in Konumlar)
{
dgExcel.Rows.Add(konum.KonumAdi, sucTurleri[0].SucTuru, DateTime.Now.ToShortDateString());
}
but i got an error and i used this
foreach (var konum in Konumlar)
{
dgExcel.Rows.Add(konum.KonumAdi, null, DateTime.Now.ToShortDateString());
DataGridViewComboBoxCell cbox = (DataGridViewComboBoxCell)dgExcel.Rows[dgExcel.Rows.Count - 1].Cells[1];
cbox.Value = sucTurleri[0].SucTuru;
}
and the error is
Your data binding part is pretty OK. The problem is with dgExcel.Rows.Add() method.
Here is a sample code:
List<Item> items = new List<Item>();
items.Add(new Item() { Name = "One", Id = 1 });
items.Add(new Item() { Name = "Two", Id = 2 });
var cbo = dataGridView1.Columns[1] as DataGridViewComboBoxColumn;
cbo.DataSource = items;
cbo.ValueMember = "Id";
cbo.DisplayMember = "Name";
dataGridView1.Rows.Add("test", items[1].Id);
...
public class Item
{
public string Name { get; set; }
public int Id { get; set; }
}
Because the DataGridViewComboBoxColumn is data bound, you have to set the value by ValueMember, in my case items[1].Id. You have to to this in your code as well.

Storing Two Values from a Dataview into a dropdown

Is there an way of storing both the ID and Test ID values in the Dropdown list but I need to display the DisplayName? I need both of these values when the item is selected
ID | TestID | DisplayName
1 | 2 | Test
Sample Code:
ddList.DataSource = DvName;
ddList.DataTextField = "DisplayName";
ddList.DataValueField = "ID"; // + "TestID" ???
You could use a delimiter to put both values together and then delimit them once you pull them out.
ddList.DataValueField = obj.ID + "~" + obj.TestID;
Otherwise you could create a dictionary that hold the ID and the Test ID, so that when you select your item from the dropdown, you can use the value field as the key to the dictionary and select the TestID.
private Dictionary<string, string> referenceValues = new Dictionary<string, string>();
referenceValues.Add("ID", "TestID");
ddList.DataValueField = "ID";
//When pulling then value back
var referencedItem = referenceValues[ddList.selectedValue];
Assuming you're getting this values from a model you could do something like:
public string NewValue
{
get
{
return ID+ "," + TestId;
}
}
ddList.DataSource = DvName;
ddList.DataTextField = "DisplayName";
ddList.DataValueField = "NewValue";
Assuming that you are using a class for each instance of your data; add another property to the class and bind to that property:
public class MyObject
{
//other stuff
public string DisplayValue
{
get { return String.Format("{0} ({1})", ID, TestID); }
}
}
ddList.DataSource = DvName;
ddList.DataTextField = "DisplayName";
ddList.DataValueField = "DisplayValue";

Categories