ComboBox behaving in a not expected way - c#

I have two comboboxes which I populate using my GetAllCities() method in the CtrlMap.
My idea is, whenever I select another city on the ddFrom it should databind all the cities to ddTo (and later on remove the exact same selected, so user won't be able to select same city as point From and To).
However, Whenever I select something on ddFrom, ddTo populates (as it should), but SelectedIndex gets the same as the ddFrom. Same goes in the opposite way. If I select a city, lets say New York on ddTo it is also selected on ddFrom.
In the GUINewBooking.Designer.cs there's only this event handler registered: this.ddFrom.SelectedIndexChanged += new System.EventHandler(this.ddFrom_SelectedIndexChanged);
ddTo has no event handler registered. Any ideas?
public partial class GUINewBooking : Form
{
private CtrlMap ctrlMap;
public GUINewBooking()
{
InitializeComponent();
ctrlMap = new CtrlMap();
ddFrom.DataSource = ctrlMap.GetAllCities();
ddFrom.DisplayMember = "name";
}
private void ddFrom_SelectedIndexChanged(object sender, EventArgs e)
{
ddTo.DataSource = ctrlMap.GetAllCities();
ddTo.DisplayMember = "name";
}
}

I believe it's because you are using the same data source. You might need to
private void ddFrom_SelectedIndexChanged(object sender, EventArgs e)
{
CtrlMap ctrlMapTo = new CtrlMap();
ddTo.DataSource = ctrlMap2.GetAllCities();
ddTo.DisplayMember = "name";
}

The answer can be found Strange behavior of Windows Forms combobox control
Each combobox DataSource property should be assigned to a different BindingSource object.
Example:
cmbDataType1.DataSource = new BindingSource(datasource, "");
cmbDataType2.DataSource = new BindingSource(datasource, "");
Or in my particular case:
ddFrom.DataSource = new BindingSource(ctrlMap.GetAllCities(), "");
ddTo.DataSource = new BindingSource(ctrlMap.GetAllCities(), "");

Related

How to get values from BindingSource in C#

I am working with WinForm in this i have 3 RadioButton one ComboBox and have three BindingSource
I want that when I check any of the RadioButtons, the values from the particular DataSources get bound to the ComboBox's ValueMember and DisplayMember.
The program has a SQL query where I want to send value based on the checked radio button.
private void rdbMed_CheckedChanged(object sender, EventArgs e)
{
cmbStock.DataSource = null;
cmbStock.DataSource = this.medicinesBindingSource;
this.cmbStock.DisplayMember = ""; //i want to bind "Med_ID" from medicinesBindingSource
this.cmbStock.ValueMember = ""; //"Med_Name"
}
private void rdbCat_CheckedChanged(object sender, EventArgs e)
{
cmbStock.DataSource = null;
cmbStock.DataSource = this.categoriesBindingSource;
this.cmbStock.DisplayMember = ""; //"category_Name"
this.cmbStock.ValueMember = ""; // category_ID"
}
private void rdbPharm_CheckedChanged(object sender, EventArgs e)
{
cmbStock.DataSource = null;
cmbStock.DataSource = this.pharmaceuticalBindingSource;
this.cmbStock.DisplayMember = "";// "Pharma_Name"
this.cmbStock.ValueMember = "";// "Pharma_ID"
}
Bellow are the parameter of the Query. It will help you to understand what I want to achieve.
if (rdbMed.Checked)
{
con.cmd.Parameters.AddWithValue("#Med_ID", cmbStock.ValueMember);
con.cmd.Parameters.AddWithValue("#category_ID", "");
con.cmd.Parameters.AddWithValue("#Pharma_ID", "");
}
else if (rdbCat.Checked)
{
con.cmd.Parameters.AddWithValue("#Med_ID", "");
con.cmd.Parameters.AddWithValue("#category_ID", cmbStock.ValueMember);
con.cmd.Parameters.AddWithValue("#Pharma_ID", "");
}
else if (rdbPharm.Checked)
{
con.cmd.Parameters.AddWithValue("#Med_ID", "");
con.cmd.Parameters.AddWithValue("#category_ID", "");
con.cmd.Parameters.AddWithValue("#Pharma_ID", cmbStock.ValueMember);
}
Easiest and the least pain way of doing this is resolving it inside SQL command and way to do it is cast your columns with AS VM and AS DM and make your DisplayMember = "DM" and ValueMember = "VM", so if you have sql query like SELECT USERID AS VM, NAME AS DM or SELECT PRODUCTID AS VM, NAME AS DM it will both work.
Problem later is if you do something with code and you may make mistakes trying to get USERID from databinding but it is instead VM. To avoid this you could "double select" values in query like SELECT USERID, NAME, ...., USERID AS VM, NAME AS DM this way you will have VM and DM for your controls but still hold original columns.

Don't display items to combobox from Entity Framework

I have defined a model in Entity Framework. Now I want to fill out the combobox from this model. But I was unsuccessful.
private void comboBox6_SelectedIndexChanged(object sender, EventArgs e)
{
using (SamenEntities c = new SamenEntities())
{
comboBox6.DataSource = c.sabt_como_tahsili.ToList();
comboBox6.ValueMember = "id_vaziat_tahsili";
comboBox6.DisplayMember = "name_vaziat_tahsili";
}
}
No data is displayed in the comboBox
You should fill your combo box when you initialize your form. Or maybe create a RefreshDataSources function which will reload every data set on your form, this combo box included. Like this maybe?
private void RefreshDataSources()
{
using (SamenEntities c = new SamenEntities())
{
#region combobox
comboBox6.DataSource = c.sabt_como_tahsili.ToList();
comboBox6.ValueMember = "id_vaziat_tahsili";
comboBox6.DisplayMember = "name_vaziat_tahsili";
#endregion
// place other controls here
}
}
But doing that in the event SelectedIndexChanged is not the best choice, even when it would work.
EDIT
Just checked the behavior of a usual microsoft combobox item.
The SelectedIndexChanged won't be launched if there is no items inside it, so no chance to execute your code.
public Form1()
{
InitializeComponent();
using (SamenEntities c = new SamenEntities())
{
comboBox6.DataSource = c.sabt_como_tahsili.ToList();
comboBox6.ValueMember = "id_vaziat_tahsili";
comboBox6.DisplayMember = "name_vaziat_tahsili";
}
}

access to property on selection winforms combobox

One article has Name and Price properties. I use Name property to display articles inside combobox cmbDataList like this
public Form1()
{
InitializeComponent();
cmbDataList.DataSource = GetData();
cmbDataList.DisplayMember = "Name";
}
After user selected the preffered article I want to use it's Price property to assign to textbox on the same form. So, how to access to that Price property?
private void cmbDataList_SelectedIndexChanged(object sender, EventArgs e)
{
//var sel = cmbDataList.SelectedItem;
}
You have to cast SelectedItem to proper object.
private void cmbDataList_SelectedIndexChanged(object sender, EventArgs e)
{
var sel = (YourObject)cmbDataList.SelectedItem;
txt.Text = sel.Price.ToString();
}
Unless all names are unique, you're going to need a unique identifier to reference, for example an articleID.
From here, set the ComboBox's ValueMember like so;
cmbDataList.ValueMember = "ID";
then you can get your value on the event handler;
private void cmbDataList_SelectedIndexChanged(object sender, EventArgs e)
{
var sel = cmbDataList.SelectedValue;
//From here you're going to need to find your article with that particular ID.
}
Alternatively. You could have your DisplayMember as the article name, and the price as the ValueMember, then get it in the event handler for SelectedIndexChanged in the same way i put above. SelectedValue will then return the price;
cmbDataList.ValueMember = "Price";
private void cmbDataList_SelectedIndexChanged(object sender, EventArgs e)
{
var yourSelectedPrice = cmbDataList.SelectedValue;
}
Assuming GetData() returns a table, you need to write the ValueMember also... like this:
InitializeComponent();
cmbDataList.DataSource = GetData();
cmbDataList.DisplayMember = "Name";
cmbDataList.ValueMember = "Price";
Now, your selected display will be synced with the value and you will be able to use it..
Get more info in here:
Populate combobox
You Need to set ValueMember You can set in this way
cmbDataList.ValueMember = "ID";
then you write the code on cmbDataList_SelectedIndexChanged Event
May be this will help you
var sel = cmbDataList.SelectedValue

How to use DataGridComboBoxColumn?

I created a DataGrid and added a DataGridComboBoxColumn programmatically.
public partial class MainWindow : Window
{
private DataGridComboBoxColumn weightColumnChar = new DataGridComboBoxColumn();
ObservableCollection<int> mComboBoxValues;
public ObservableCollection<int> ComboBoxValues
{
get { return this.mComboBoxValues; }
set { this.mComboBoxValues = value; }
}//end property
public MainWindow()
{
InitializeComponent();
mComboBoxValues = new ObservableCollection<int>() {-1, 0, 1 };
}//end constructor
private void Window_Loaded(object sender, RoutedEventArgs e)
{
weightColumnChar.Header = "Weight";
dataGrid_Char.Columns.Add(weightColumnChar);
weightColumnChar.ItemsSource = ComboBoxValues;
Binding binding = new Binding();
binding.Path = new PropertyPath(ComboBoxValues[1]);
weightColumnChar.SelectedItemBinding = binding;
}//end method
private void dataGrid_Char_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}//end method
//Opens ComboBox on first click
private void dataGrid_Char_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource.GetType() == typeof(DataGridCell))
{
DataGrid grd = (DataGrid)sender;
grd.BeginEdit(e);
}//end if
}//end method
}//end class
I added an ItemsSource to it and retrieve the values from an ObservableCollection.
The values from the collection are shown in runtime.
My problem is that if I select a value from the ComboBox this vlaue isn't selected and displayed afterwards. What am I doing wrong?
And I also want to select a default value. How does that work?
Please explain programmatically and not in XAML!
Would be great if anybody could help me.
Thanks!!!
First of all you haven't shown what your underlying collection is that is bound to the DataGrid.
You'll need something like DataGrid.ItemsSource = new ObservableCollection<MyClass>(); (it has to be a collection that supports change notification, thus I chose ObservableCollection).
Secondly you are binding the ComboBox.SelectedItemBinding to the ComboBox.ItemsSource which is nonsense. ComboBox.ItemsSource is the collection of values you can choose from, ComboBox.SelectedItemBinding (I would actually use ComboBox.SelectedValueBinding) is the "path" to the underlying data source that contains/reprsents the final value (eg. MyClass.IntProperty). So you select a value from a collection and assign that to some data item (you cannot assign it back to the collection where you select from).
PS! In case you later use something that resembles a KeyValuePair (eg. Id; Name) as your ComboBox.ItemsSource, then you set ComboBox.SelectedValuePath = Id; ComboBox.DisplayMemberPath = Name;. MyClass.IntProperty would contain the Id value in such a case.

How to 2-way bind a textbox in a template fields programmatically

I have a gridview to which I'm adding template fields programmatically. Each of the template fields have a textbox. I would like to make this text box have 2-way binding to a database column. Please see below code.
public class CustomEditItemTemplate : ITemplate
{
private DataControlRowType templateType;
private string columnName;
public CustomEditItemTemplate(DataControlRowType type, string colname)
{
this.templateType = type;
this.columnName = colname;
}
public void InstantiateIn(System.Web.UI.Control container)
{
TextBox tb = new TextBox();
tb.ID = columnName;
tb.DataBinding += new EventHandler(this.tb_DataBinding);
container.Controls.Add(tb);
}
private void tb_DataBinding(Object sender, EventArgs e)
{
TextBox t = (TextBox)sender;
DetailsView dv = (DetailsView)t.NamingContainer;
//This line does only one way binding. It takes the rows from the database and displays
//them in the textboxes. The other way binding is not done. This is why my code fails
t.Text = DataBinder.Eval(dv.DataItem, columnName).ToString();
}
}
I'm calling the above class as follows
tf = new TemplateField();
tf.HeaderText = "My First Names";
tf.EditItemTemplate = new CustomEditItemTemplate(DataControlRowType.DataRow, "firstName");
dvModify.Fields.Add(tf);
How can I make the text box such that when I edit the text, this change is reflected in the database as well?
Thanks for your time everyone
Perhaps you could changed the line t.Text = DataBinder.Eval(dv.DataItem, columnName).ToString(); to something like t.Text= string.Format("<%# Bind(\"{0}\") %>", columnName); ?
This is just a guess...
If that doesn't work, I found some articles that actually write new classes for handling two way databinding:
Article at CodeProject circa 2005
Article at Programmer's Heaven
Hopefully one of these options will be useful.
It's actually not too bad to do template fields programatically, after you've seen it once, of course. Here's how we do it, abridged:
TemplateField tf = new TemplateField();
//Do some config like headertext, style, etc;
tf.ItemTemplate = new CompiledTemplateBuilder(delegate(Control container)
{
//Add the regular row here, probably use a Label or Literal to show content
Label label = new Label();
lable.DataBinding += delegate(object sender, EventArgs e)
{
label.Text = ((MyDataType)DataBinder.GetDataItem(label.BindingContainer)).MyLabelDataField;
};
});
tf.EditItemTemplate = new CompiledBindableTemplateBuilder(delegate(Control container)
{
//Here we do the edit row. A CompiledBindableTemplateBuilder lets us bind in both directions
TextBox text = new TextBox();
text.DataBound += delegate(object sender, EventArgs e)
{
text.Text = ((MyDataType)DataBinder.GetDataItem(text.BindingContainer)).MyLabelDataField;
}
},
delegate(Control container)
{
OrderedDictionary dict = new OrderedDictionary();
dict["myLabelDataColumn"] = ((TextBox)container.FindControl(text.ID)).Text;
return dict;
});
So here's what's going on. We use CompiledBindableTemplateBuilder and CompiledTemplateBuilder to actually build our template field's contents. Using a delegate is just an easy way to set this up.
The key to answering your question is in the second argument to the CompiledBindableTemplateBuilder, which is a delegate establishing the binding. After an edit, during submit, the template field will call ExtractValuesFromCell and recover an IBindableTemplate, from which it will extract a Dictionary and then pull the value(s) out of it, adding them to it's own dictionary which eventually gets turned into the uploaded data. So that's why you return an OrderedDictionary from the Binding delegate. Hope that helps!

Categories

Resources