Get index by value regarding combobox for win apps c# - c#

we can easily get index of combobox using FindString method
int index = cboCountryTwoCode.FindString(localJob.DeliveryCountryTwoCode.Trim());
cboCountryTwoCode.SelectedIndex = index;
so i just need to know is there any way to get index of combobox just finding by value instead of finding by text. please let me know is there any similar. if anything not there then how to achieve my objective that get index of combobox just finding by value. thanks
this way i am populating my combo
cboCountryTwoCode.DataSource = Utility.LoadCountry();
cboCountryTwoCode.DisplayMember = "CData";
cboCountryTwoCode.ValueMember = "CValue";
LoadCountry() will return datatable . thanks

In WinForms, ComboBox doesn't have an explicit key/value list of items. It has an ObjectCollection for Items.
I think you could implement ToString() on your objects to display its proper descriptions.
Then you should use some LINQ to find the correct item. Something like this:
class MyType
{
public int Id { get; set; }
public string Description { get; set; }
public override string ToString()
{
return Description;
}
}
var selectedObject = cb.Items.Cast<MyType>().SingleOrDefault(i => i.Id.Equals(myId));

Related

How to display custom field type on data grid view? [C# / WinForms]

I have employee class, which has field of type ISalary (Interface). In data grid view, I want to display that salary, but what I get is empty field. Is it any possible way to display that "custom type field" in data grid view? invoking toString method would help, but I can't understand how to do that.
Here is how I am binding data:
employeeBindingSource.DataSource = employeesList;
All fields in that list, ofc is not null. And here is some of my class, which list I want to display:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public int DepartmentId { get; set; }
// how to display this?
public ISalary Salary { get; set; }
...
}
I did some research and could not find any example on it. Or maybe was not trying hard enough.:/
Since you are using a interface as type of property, you can not override ToString method for that ISalary type without knowing the concrete type. So if you know a Salary class which implemented that interface and used instead of that interface at run-time, you can override ToString of that type.
But, in general it's not a good idea to rely on ToString of that concrete type, this way your program will be tightly relied on the concrete type and will loose its goal in using the interface.
Instead, you can use either of these options:
Use CellFormatting event to provide display value.
Use a DataGridViewComboBoxColumn which contains a List<Salary> but, set its display style property to nothing to not show dropdown button.
Use a readonly property in Employee class which return a known property of ISalary, like return this.Salary.SomeProperty;
And still there are more options. To see some other options and examples, take a look at this post: How to bind a column from second level list on bindsource in winforms datagridview or this one: Show Properties of a Navigation Property in DataGridView (Second Level Properties).
This should work for you:
public ISalary Salary
{
get{ return this.Salary.ToString(); };
set;
}
To use ToString(), you only append it at the end of the object you want to be returned as a string.
See the official MSDN on the ToString() function:
Object.ToString Method
interface ISalary
{
public decimal Amount { get; set; }
public string GetSalaryString();
}
the code:
List<Employee> lstEmployee = GetEmployeeList();
dataGridView1.Rows.Clear();
if (lstEmployee.Count == 0)
return;
foreach (var employee in lstEmployee)
{
DataGridViewRow dgvr = dataGridView1.Rows[dataGridView1.Rows.Add()];
dgvr.Cells[colnId.Index].Value = employee.Id;
dgvr.Cells[colnName.Index].Value = employee.Name;
dgvr.Cells[colnGender.Index].Value = employee.Gender;
dgvr.Cells[colnDepartmentId.Index].Value = employee.DepartmentId;
dgvr.Cells[colnSalary.Index].Value = employee.Salary.GetSalaryString();
}

c# How to call existing item of form having its name stored in new string?

I have multiple datagrids and i would like to move data from one to another.
The problem is:
I have their names "made" into string variables:
string gridfrom = "datagrid" + cplist1.SelectedItem.ToString();
string gridto = "datagrid" + cplist2.SelectedItem.ToString();
In this case, i know that gridfrom = datagridMAR and gridto = datagridAPR
But gridfrom and gridto changes according to the listboxes selected items.
How do i call these objects (already existing in the form) to change its properties? For example:
gridto.DataSource = gridfrom;
Thanks in advance
Let me tell you an elegant way of dealing with this situation without getting into dynamic type loading, etc
Create a custom type, say
class GridName {
public DataGridView Grid {get; private set;}
public string Name {get; private set;}
public GridName(DatagridView grid, string name) {
Grid = grid;
Name = name;
}
public string override ToString() {
return Name;
}
}
Now, instead of adding a string into the cplist1 and cplist2, simply add GridName object into it. It will display the name correctly and also when you want the grid associated with it, you can access the .Grid property
There are many other ways of doing it. For example, you can use ValueMember and DisplayMember property.
I would definitely resist against trying to convert the grid name into a DatagridView object.

Validating a large dictionary of set strings with user input

I have a profile form that has a lot of user selections and I am sort of stumped on a good approach to validate what the user enters, when passing validation mapping those values to object properties.
For example I have a dictionary
public static Dictionary<string, string> objProfileSelections = new Dictionary<string, string>();
public static string MySelections(string key)
{
objProfileSelections.Add("1", "No Answer");
objProfileSelections.Add("3", "Less Than $25,000");
objProfileSelections.Add("5", "$35,000 to $50,000");
objProfileSelections.Add("7", "$50,000 to $75,000");
objProfileSelections.Add("9", "$75,000 to $100,000");
objProfileSelections.Add("11", "$100,000 to $150,000");
objProfileSelections.Add("13", "$150,000+");
objProfileSelections.Add("2", "No Answer");
objProfileSelections.Add("4", "Less Than $25,000");
objProfileSelections.Add("6", "$35,000 to $50,000");
objProfileSelections.Add("8", "$50,000 to $75,000");
objProfileSelections.Add("10", "$75,000 to $100,000");
objProfileSelections.Add("12", "$100,000 to $150,000");
objProfileSelections.Add("14", "$150,000+");
string item;
objProfileSelections.TryGetValue(key, out item);
return item;
}
Id like to pass in a list of key strings from the user and pass those items to populate an object. The issue is I don't know how to code it so it know which property to go to, I looked at reflection, but I couldn't find any examples that have a set dictionary of values that map to property names.
To make a bit more clear, when a user makes a selection it passes as a parameter in the dictionary, and the dictionary outputs the items. From key 1 comes value No Answer. If the user selected all the check boxes it would be value - (1,3,5,7,9,11,13). I need to extract those values when there is a matching key to a matching property. For example if the user clicks 1,5 but leaves the rest unchecked, how do I know which selections the user made? How do I get the program to know which property to populate based on the results?
*edit
some properties I would like it mapped to
public string MyAnnualIncome{ get; set; }
public List<string> InterestAnnualIncome{ get; set; }
So the first property would be taking one value, and the second property would be taking multiple values.
When a key matches a value comes out the dictionary, I would need the odd values going to MyAnnualIncome and the even values going to InterestAnnualIncome.
so no one is confused odd and even keys are set up for a purpose, odd numbers belonging to a certain group of properties and the even ones belonging to another based on the html selections (even being my selections, odd being what I am interested in)
*Update
Is there a way I can possibly use the keys like 1,3,5 and pass that into a list using the except extension method. Then take the results and use a method to convert the values from enumerated data types to strings?
Hopefully I understood your question.
I would add a small helper class (this is a solution which doesn't use reflection, but uses delegates instead):
public class PropertyModifier
{
private string text;
private Func<string> modifier;
public PropertyModifier(Func<string> modifier)
{
this.modifier = modifier;
}
public PropertyModifier With(string text)
{
PropertyModifier newModifier = new PropertyModifier(modifier);
newModifier.text = text;
return newModifier;
}
public void Modify()
{
modifier(Text);
}
}
Then I would rewrite your code and have the dictionary map to this class instead to string:
public static Dictionary<string, PropertyModifier> objProfileSelections = new Dictionary<string, PropertyModifier>();
public static MyUserProfile Profile; //Assuming this is the object you want to modify
public static string MySelections(string key)
{
PropertyModifier myIncome = new PropertyModifier(text => Profile.MyAnnualIncome = text);
PropertyModifier interestIncome = new PropertyModifier(text => Profile.InterestAnnualIncome.Add(text));
objProfileSelections.Add("1", myIncome.With("No Answer"));
objProfileSelections.Add("3", myIncome.With("Less Than $25,000"));
...
objProfileSelections.Add("2", interestIncome.With("No Answer"));
objProfileSelections.Add("4", interestIncome.With("Less Than $25,000"));
...
}
Then, when processing the user's selection, get the mapped PropertyModifier from the dictionary and call its Modify method.
I tried in this code to illustrate how you can modify the properties of the different classes that may compose a profile. Modifications are done by reflection only, i.e. just providing the class name, the property name that will vary in each class and the string value to be assigned to the property.
Not sure that it fits your expectations :(
Profile profile = new Profile() ;
profile.SetPropertyValue("hair","color","brown") ;
internal class Profile()
{
private Hair hair_ = new Hair();
private Job job_ = new Job ();
internal Hair hair { get { return hair_ ; } }
internal Job job { get { return job_ ; } }
private void SetPropertyValue(string profileItemName, string ItemPropertyName, string value)
{ // it is assumed that the different items (hair or job) of the Profile are accessible
// with a a property
// first find the Item object, i.e. hair or job
object itemObj = this.GetType().GetProperty(profileItemName).GetValue(this,null);
// assign to Item property the input value, e.g. hair.color=Brown
itemObj.GetType().GetProperty(ItemPropertyName).SetValue(itemObj, value, null);
}
}
internal class Hair()
{
private string color_ ;
private string style_ ;
internal string color { get { return color_ ; } set {color_ = value ; } }
internal string style { get { return style_ ; } set {style_ = value ; } }
}

Generated a list of filenames, but no file paths

I have a list box that displays a set of filenames that reference text files. I think it is aesthetically unappealing to display full paths, so I used Path.GetFileName to cut off the directory part.
But now when the user selects a particular filename to open, I've lost the paths. The files could be located anywhere on the local computer (for now).
How can I use the list box so that I can display nice filenames, but also have reference to the actual file?
EDIT: I like the idea of having a custom wrapper class for each list box item.
What's I've done in the past is create a wrapper class for the objects I want to display in the ListBox. In this class override ToString to the string you want to display in the ListBox.
When you need to get details of a selected item, cast it to the wrapper class and pull the data you need.
Here's an ugly example:
class FileListBoxItem
{
public string FileFullname { get; set; }
public override string ToString() {
return Path.GetFileName(FileFullname);
}
}
Fill your ListBox with FileListBoxItems:
listBox1.Items.Add(new FileListBoxItem { FileFullname = #"c:\TestFolder\file1.txt" })
Get back the full name of a selected file like this:
var fileFullname = ((FileListBoxItem)listBox1.SelectedItem).FileFullname;
Edit
#user1154664 raises a good point in a comment to your original question: how would a user differentiate two ListBox items if the displayed file names are the same?
Here are two options:
Also display each FileListBoxItem's parent directory
To do this change the ToString override to this:
public override string ToString() {
var di = new DirectoryInfo(FileFullname);
return string.Format(#"...\{0}\{1}", di.Parent.Name, di.Name);
}
Display a FileListBoxItem's full path in a tooltip
To do this drop a ToolTip component on your form and add a MouseMove event handler for your ListBox to retrieve the FileFullname property value of the FileLIstBoxItem the user is hovering the mouse over.
private void listBox1_MouseMove(object sender, MouseEventArgs e) {
string caption = "";
int index = listBox1.IndexFromPoint(e.Location);
if ((index >= 0) && (index < listBox1.Items.Count)) {
caption = ((FileListBoxItem)listBox1.Items[index]).FileFullname;
}
toolTip1.SetToolTip(listBox1, caption);
}
Of course you can use this second option with the first.
Source for the ToolTip in a ListBox (the accepted answer, code reformatted to a flavor I prefer).
Use ListBoxItem.Tag to store the full path for each item if using WPF. Or, if using WinForms, you can create a custom class that stores the full path, but overrides object.ToString() so that only the filename is displayed.
class MyPathItem
{
public string Path { get; set; }
public override string ToString()
{
return System.IO.Path.GetFileName(Path);
}
}
...
foreach (var fullPath in GetFullPaths())
{
myListBox.Add(new MyPathItem { Path = fullPath });
}
I do this
public class ListOption
{
public ListOption(string text, string value)
{
Value = value;
Text = text;
}
public string Value { get; set; }
public string Text { get; set; }
}
Then create my list
List<ListOption> options = new List<ListOption>()
For each item in files
options.Add(new ListOption(item.Name, item.Value));
Next
bind my list
myListBox.ItemSource = options;
Then get my value or text
protected void List_SelectionChanged(...)
{
ListOption option = (ListOption) myListBox.SelectedItem;
doSomethingWith(option.Value);
}
Just the idea here is main thing
Personally I don't agree with you sentiment that this is ugly for the user. Showing the full path gives the explicit details to the user and enable them to have confidence in their selection or what ever they are doing.
I would use a Dictionary, using the item index as the Key and the full path of this list item as the value.
Dictionary<int, string> pathDict = new Dictionary<int, string>();
pathDict.Add(0, "C:\SomePath\SomeFileName.txt");
...
The above is probably the best way to go here over using the item.Tag property...
I hope this helps.

Howto determine order of displayed columns in a datagridview binded to a datasource

Is there a way to determine the order of the columns displayed in
a datagridview when binding it to a datasource whitch contains an
underlying IList ?
I thought there was a specific property attribute for this purpose
but can't recall what it actually was.
eg:
public void BindToGrid(IList<CustomClass> list)
{
_bindingSource.DataSource = list;
dataGridView1.DataSource = _bindingSource.DataSource;
}
Type binded should be something like this
class CustomClass
{
bool _selected = false;
//[DisplayOrder(0)]
public bool Selected
{
get { return _selected; }
set { _selected = value; }
}
string _name;
//[DisplayOrder(2)]
public string Name
{
get { return _name; }
set { _name = value; }
}
string _value;
//[DisplayOrder(1)]
public string Value
{
get { return _value; }
set { _value = value; }
}
}
Edit:
I would like to add that I rather not want to add the columns manually to columns list in the designer. I'd like to keep this as dynamic as possible.
In the DataGridView specify an actual list of columns instead of allowing it to auto-databind. You can do this in Design View in Visual Studio by selecting the control and adding the columns. Make sure you specify in each column which property it should bind to. Then you can rearrange the columns any way you want as well as do other customizations.
I think that the DisplayOrder attribute is relatively new and probably not supported in the DataGridView control.
The display order of the columns in the DataGridView is determined by the DisplayIndex properties of the DataGridViewColumn-s. You would have to set these properties on the columns of the grid, in order to change their order.
I also agree with Eilon's answer: you can create the list of the columns yourself, instead of auto-databinding, and that way you can determine the order in which they will be displayed.
The column ordering does not always work. You'll need to turn off AutoColumnCreate to fix inconsistencies:
http://www.internetworkconsulting.net/content/datadridview-displayorder-not-working
I am not sure whether this is a functionality that .Net Offers, but if you just change the order of your properties in the class, the grid renders the columns in the same order.
The below two classes will render in the order they are typed in the class. Strange!!
class CustomClass
{
public bool Selected {get;set;}
public string Name{get;set;}
}
class CustomClass
{
public string Name{get;set;}
public bool Selected {get;set;}
}

Categories