I have a dialog form where the user has to selected which colums from a textfile he wants to use for drawing a graph.
If someone doesn't quite understand what I mean, please look at the following example:
The dialog opens
The user selects e.g. that the x-values of his graph shall be from the second column of the textfile
The user selects e.g. that the y-values of his graph shall be from the third column of the textfile
The user clicks "OK"
The problem I have is the following:
I want to prevent the user from selecting the same column for x and y values, which would result in a line in an angle of probably 45 degrees and make the graph useless.
Both comboboxes are filled with the same array of strings, which contains the headlines of the columns in the textfile. Getting those strings into the comboboxes works great, but:
I tried removing the item selected in one combobox from the other combobox and otherwise.
Before that, the currently selected item is stored in a variable and the items are reset to the default state, which means all headlines from the textfile.
But, as I programmatically set the index to where it was before, so that the user doesn't have to, the SelectedIndexChanged event fires and traps my code in an infinite loop.
public void setComboboxText()
{
cbX.Items.Clear();
cbY.Items.Clear();
cbX.Items.AddRange(cbText);
cbY.Items.AddRange(cbText);
}
void CbXSelectedIndexChanged(object sender, EventArgs e)
{
var item = cbX.SelectedItem;
setComboboxText();
cbX.SelectedItem = item;
cbY.Items.Remove(cbX.SelectedItem);
}
void CbYSelectedIndexChanged(object sender, EventArgs e)
{
var item = cbY.SelectedItem;
setComboboxText();
cbY.SelectedItem = item;
cbX.Items.Remove(cbY.SelectedItem);
}
The code does the following:
The currently selected item is temporarily stored
The items of the combobox are reset
The currently selected item is set to be the item stores before
The item selected in the changed box disappears from the other combobox
Any help appreciated, especially if someone could tell me if I can do what I want with another event or even without events.
Thanks in advance
I think this is what you are trying to achieve.
public partial class Form1 : Form
{
List<string> source1 = new List<string>();
List<string> source2 = new List<string>();
public Form1()
{
InitializeComponent();
for (int i = 0; i < 10; i++)
{
source1.Add("item" + i);
source2.Add("item" + i);
}
comboBox1.Items.AddRange(source1.ToArray());
comboBox2.Items.AddRange(source2.ToArray());
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox2.Items.Contains(comboBox1.SelectedItem))
{
comboBox2.Items.Clear();
List<string> updatedList = new List<string>();
updatedList = (from x in source2
where !x.Equals(comboBox1.SelectedItem)
select x).ToList<string>();
comboBox2.Items.AddRange(updatedList.ToArray());
}
}
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.Items.Contains(comboBox2.SelectedItem))
{
comboBox1.Items.Clear();
List<string> updatedList = new List<string>();
updatedList = (from x in source1
where !x.Equals(comboBox2.SelectedItem)
select x).ToList<string>();
comboBox1.Items.AddRange(updatedList.ToArray());
}
}
}
Make the source collections available avaiable to each combobox SelectedIndexChanged handlers
On each selection change update the source of the other combobox only if the newly selected item exists in the other combobox Items.
Related
I am confronting with an issue with the ComboBox in a WinForms app. The combo box contains a list with items that are grabbed from a TXT file. To read and update the list I added the following code to Form_Load.
string[] lineOfContents = File.ReadAllLines(Application.StartupPath + #"Items.txt");
foreach(var line in lineOfContents)
{
string[] tokens = line.Split(',');
ComboBox.Items.Add(tokens[0]);
}
All nice and good, the list does update. However, I also have some TextBoxes that are changing their text based on the string of the selected item in the ComboBox. For example, when the selected item in the ComboBox is "Example", the text in the first text box should change from empty to "I am an example!", but it doesn't and remains empty. The code for it is:
if(ComboBox.SelectedItem == "Example")
{
TextBox.Text = "I am an example!";
}
At first I though it's a conversion issue so I tried to use Convert.ToString(tokens[0]); but it did not work as well.
Any suggestions on what I should try next to fix this issue?
You are describing bound behavior so the first thing to check is whether the TextBox is properly connected to the event fired by the ComboBox. Something like this would be the first step to getting the behavior you describe.
public MainForm()
{
InitializeComponent();
// Subscribe to the event here OR using the Designer
comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.Text == "Example")
{
textBox1.Text = "I am an example!";
}
else textBox1.Text = comboBox1.Text;
}
But the missing step in the code you posted is actually selecting a value in the combo box after the tokens are loaded into it. This leaves the text box blank as demonstrated here:
private void buttonLoad_Click(object sender, EventArgs e)
{
loadMockFile();
}
private void loadMockFile()
{
string[] lineOfContents = MockFile;
foreach (var line in lineOfContents)
{
var token =
line.Split(',')
.Select(_ => _.Trim())
.Distinct()
.First();
if (!comboBox1.Items.Contains(token))
{
comboBox1.Items.Add(token);
}
}
}
string[] MockFile = new string []
{
"Example, A, B,",
"Other, C, D,",
};
So the solution is to make sure that you make a selection after the tokens are loaded into the ComboBox, for example as shown in the handler for the [Load + Select] button:
private void buttonLoadPlusSelect_Click(object sender, EventArgs e)
{
loadMockFile();
var foundIndex = comboBox1.FindStringExact("Example");
comboBox1.SelectedIndex = foundIndex;
}
I have 2 windows forms. One form with datagridview and button, and the other form with labels. More or less like Master-Detail design. I have 2 related tables in database. I can fill the datagridview nicely with data from the main table. First I select data on datagridview, and I want to use the button to display the values on the labels located on another form.
Once data is loaded on datagridview; I use the following code for the methods to filter the underlying tables based on selection made from datagridview:
[form 2]
public DataView EnterpriseView()
{
foreach (DataGridViewRow row in Viewer.SelectedRows)
identifier = row.Cells["BusinessName"].Value.ToString();
var EnterpriseVw = new DataView(EnterpriseDT)
{
RowFilter = "BusinessName = '" + identifier + "'"
};
return EnterpriseVw;
}
After returning the view, I want to use the button to push the information to another form that has the labels. I'm not sure about how to get this working. I tried different codes of my own, and it doesn't work
My issue how to code the button_click event. And is there another event I need to call for this to work? How does the button know if I have selected something on the datagridview? How does the datagridview know I have clicked the button? I tied something like this for the button:
[form 2]
private void button1_Click(object sender, EventArgs e)
{
index = Viewer.SelectedRows[0].Index;
Viewer.Rows[index].Selected = true;
//EnterpriseView();
//DetailsView();
//this.Click += new EventHandler(Viewer_SelectionChanged);
if (Viewer.Rows[index].Selected == true)
{
var frm1 = new form1(); //form with labels
//foreach(DataGridViewRow row in Viewer.SelectedRows)
frm1.Publish(); //method that assigns data to labels
}
It doesn't work
I tried using somthing like this for the labels:
[form 1]
public void Publish()
{
var frm2 = new form2();
var vEnterprise = frm2.EnterpriseView();
Email.DataBindings.Add("Text", vEnterprise, "EmailAddress");
}
To Get values from Selected Row of the DataGridView you need to change some properties :
First You need to set SelectionMode to FullRowSelect.
Second You need to set MultiSelect to False.
You can do it through the properties tab.
Then we can use dataGridView1.SelectedRows it will return DataGridViewSelectedRowCollection a list of the selected rows, but since we disabled multiSelect there will always be just one so we can use [0].
Now in the Button_click event Handler
private void button1_Click(object sender, EventArgs e)
{
// To Get The Selected Row
var dr = dataGridView1.SelectedRows[0];
// The Cells Property is going to return DataGridViewCellCollection a list again
// Basically the columns so the first one will be the first column and so on
string item1 = dr.Cells[0].Value.ToString();
string item2 = dr.Cells[1].Value.ToString();
string item3 = dr.Cells[2].Value.ToString();
}
In the Form with the labels Define a second constructor.
Say we Have 3 Labels
We gonna define a second constructor that takes 3 Strings, Like this
public TheSecondForm(String S1, String S2,String S3)
{
label1.Text = S1;
label2.Text = S2;
label3.Text = S3;
}
Then The button Event Handle will become like this :
private void button1_Click(object sender, EventArgs e)
{
var dr = dataGridView1.SelectedRows[0];
string item1 = dr.Cells[0].Value.ToString();
string item2 = dr.Cells[1].Value.ToString();
string item3 = dr.Cells[2].Value.ToString();
// What was added
TheSecondForm frm2 = new TheSecondForm(item1, item2, item3);
frm2.Show();
}
By Now the labels will be populated.
I'm making an application that consists of comboBoxes. If the user selected "Chauffeur" in the comboBox the total price goes up by 10% once my btnAddDriver is clicked. However when I select "Chauffeur" the total price does not increase by 10% when I click Add Driver in fact when using brake points it doesn't seem to realise I have selected "Chauffeur" and skips the calculation within the if statement.
My Code is as fallows
int policy = 500;
double Chauffeur = 0.10;
private void cmbOccupation_Loaded(object sender, RoutedEventArgs e)
{
// ... A List.
List<string> occupation = new List<string>();
occupation.Add("Chauffeur ");
occupation.Add("Accountant");
// ... Get the ComboBox reference.
var comboBox = sender as ComboBox;
// ... Assign the ItemsSource to the List.
comboBox.ItemsSource = occupation;
// ... Make the first item selected.
comboBox.SelectedIndex = 0;
}
private void btnAddDriver_Click(object sender, RoutedEventArgs e)
{
txtPolicy.Text = policy.ToString();
if (cmbOccupation.SelectedItem.ToString() == "Chauffeur")
{
txtPolicy.Text = (policy * Chauffeur).ToString();
}
}
"Chauffeur" and "Chauffeur " are two different strings in C#.
That'll be $150, please pay the girl at the desk on your way out.
Change occupation.Add("Chauffeur ");
To occupation.Add("Chauffeur");
Say, I have a TextBox - When the User enters contents into TextBox and Click on Add the Content Should Populate in the DataGrid Without any db connectivity. The User Can add repeated items in the TextBox and Click on Add, So Every Value gets Popluated in the Grid.
How do I achieve this?
You can try something like this, first you have to Imports the System.Collection.Generic namespace
private List<string> addContent(string content)
{
//create a generic list of string type
List<string> s = new List<string>();
for (int i = 0; i < 10; i++)
{
s.Add(content);
}
return s;
}
protected void btnAdd_Click(object sender, EventArgs e)
{
//Passed the List<> as DataSource and then bind the content in the list<> in the DataGrid
this.DataGrid1.DataSource = this.addContent(this.txtadd.Text);
this.DataGrid1.DataBind();
}
I Hope this works for you
My windows form has an ADD button which adds a combo box to the form after each click. The problem is, i am not able to bind it to a table column at run time. Using an existing databinding source selects the same value in all the combo boxes. I am coding in C#
here is the sample code :
ComboBox ocbNext = new ComboBox();
//HAVE set the rest of the properties right, the problem is with the databinding
ocbNext.DataSource = this.dummysubjectBindingSource;
ocbNext.DisplayMember = "sub_name";
ocbNext.ValueMember = "sub_name";
this.Controls.Add(ocbNext);
I added a DataSet to the solution and droped the Employees table (from Northwind) in the designer, which automatically created the employeesBindingSource. I dropped a combobox and a button on the Form and I set the DataSource and DataMember of the combo. Then I handled some events:
private void Form1_Load(object sender, EventArgs e)
{
this.employeesTableAdapter.Fill(this.dS.Employees);
}
private int _i = 0;
private void button1_Click(object sender, EventArgs e)
{
ComboBox combo = new ComboBox();
combo.DataSource = this.employeesBindingSource;
combo.DisplayMember = this.dS.Tables[0].Columns[++_i].ColumnName;
combo.Location = new Point(comboBox1.Location.X, comboBox1.Location.Y + comboBox1.Height * _i);
this.Controls.Add(combo);
}
So on each click, a new combo is added onto the form dynamically right under the previous combo. The combo is also bound to the next column in the Employees table (no boundary checks however).
As you can see, this is pretty easy stuff. Hope this helps.
Okay, so here is a variation of the code that could help you with that other question you asked in the comments of this answer.
It assumes you have a Form with a button and a DataSet with table Employees. On button click it creates a combo, and fills it with data (the Name column of Employees). Each time you add a combo, it gets its own copy of the data (this is important to be able to remove items from one combo at a time). Then, every time you select a value in the combo, the combo is disabled and the other combos don't have that selected value in their list.
private int _i = 0;
private void button1_Click(object sender, EventArgs e)
{
DataSet dataS = dS.Clone();
this.employeesTableAdapter.Fill((DS.EmployeesDataTable)dataS.Tables[0]);
BindingSource bindSource = new BindingSource(dataS, "Employees");
ComboBox combo = new ComboBox();
combo.Name = this.dS.Tables[0].Columns[0].ColumnName + (++_i).ToString();
combo.DataSource = bindSource;
combo.DisplayMember = this.dS.Tables[0].Columns[1].ColumnName; //This column is the Name of Employee
combo.Location = new Point(button1.Location.X, button1.Location.Y + combo.Height * _i);
combo.SelectedIndexChanged += new EventHandler(comboBox_SelectedIndexChanged);
this.Controls.Add(combo);
}
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (Control ctrl in this.Controls)
{
if (ctrl is ComboBox && ctrl != sender && ctrl.Enabled)
{
((BindingSource)((ComboBox)ctrl).DataSource).RemoveAt(((ComboBox)sender).SelectedIndex);
}
}
((ComboBox)sender).Enabled = false;
}
This is pretty close to what you require, or easily adaptable to meet your expectations. Enjoy and please select an answer as the accepted one. Thanks!
Option 1: Fill the combobox with strings:
this.comboBox1.Items.Add("Syed");
this.comboBox1.Items.Add("Baqar");
Option 2: Fill the combobox with an array of strings:
this.comboBox1.Items.AddRange(new object[] { "Syed", "Baqar" });
You need to add controls to the parent window first, and then set the data source.
ComboBox ocbNext = new ComboBox();
this.Controls.Add(ocbNext);
ocbNext.DisplayMember = "sub_name";
ocbNext.ValueMember = "sub_name";
ocbNext.DataSource = this.dummysubjectBindingSource;
Should be fine if you create a new local ComboBox variable in the clickevent. If you use a global variable for the ComboBox this might explain your problems. But without a sample how you're doing it's hard to see what's really happening, so think this is just a rough guess