I have to write a program (C#, WPF), where data is retrieved from ~30 TextBoxes. I'd like to cycle the textboxes through. I tried to create an array of textboxes, but it didn't work very well because in every method I had to repeatedly reinitialize this array.
TextBox[] subjects = { textBox1, textBox2, textBox3, textBox4, textBox5, textBox6, textBox7, textBox8, textBox9, textBox10 };
TextBox[] credits = { textBox11, textBox12, textBox13, textBox14, textBox15, textBox16, textBox17, textBox18, textBox19, textBox20 };
TextBox[] marks = { textBox21, textBox22, textBox23, textBox24, textBox25, textBox26, textBox27, textBox28, textBox29, textBox30 };
Subject.SubjectName = subjects[selection].Text;
Subject.AmountOfCredits= Convert.ToInt32(credits[selection].Text);
Subject.Mark = Convert.ToInt32(marks[selection].Text);
Main question is, if there is any other way to cycle through all those controls without creating arrays of textboxes?
Thanks in advance.
You could bind each textbox to a property. Then in the setter of each property, you would set the appropriate value in your array.
public class test
{
private string[] _textBoxes;
// constructor
public test()
{
_textBoxes = new string[30];
}
// bind your textboxes to a bunch
// of properties
public string Property0
{
get
{
return _textBoxes[0];
}
set
{
_textBoxes[0] = value;
OnPropertyChanged("Property0");
}
}
}
Have you considered using a DataGrid control? You could have three columns (Subjects, Credits and Marks) and easily get to the selected record via the SelectedItem property?
The other option is to use an ItemsControl. You could style the ItemTemplate to have three textboxes, which you databind to the properties of Subject directly. The ItemsControl's ItemsSource would then be bound to an observable collection of Subjects. For more information on how to do this, go to Microsoft's help on Data Templating Overview.
Can't you make the arrays global to the form rather than local to a method? That way you would only create the arrays once (perhaps inside the form's Load() event).
If making the control arrays global is not an option, you could lookup the controls by name (although this is somewhat slower than your array method)
string idx = (selection + 1).ToString(); // convert selection to 1-based index string
TextBox subjectText = (TextBox)FindControl("textBox" + idx);
TextBox amtCreditsText = (TextBox)FindControl("textBox1" + idx);
TextBox marksText = (TextBox)FindControl("textBox2" + idx);
Related
How to make a drop-down list when you click on an element of a specific table column in which you can select an element for this cell? Column is auto generated.
A Combobox in xaml/wpf is used like this:
<ComboBox x:Name="some Name" SelectionChanged="comboboxChanged">
<ComboBoxItem>The Content of your Combobox</ComboBoxItem>
</Combobox>
ComboBoxItems are essentially the dropdown part. You can add as many as you want.
In your back end (c#) you can get the selected Value as soon as the "SelectionChanged"-event is triggered. The code for getting the selected Value can be done multiple ways. Example:
private void comboboxChanged(object sender, SelectionChangedEventArgs e){
string comboboxvalue = comboboxname.Text;
//Then set associated textblock or label
labelname.Content = comboboxvalue;
}
The code above would be static though. Dynamically generating these elements could look like this for instance.
When auto-generating, using an inline function for the event is easy.
for (int i = 0; i < 10; i++){
ComboBox comboboxname = new ComboBox();
comboboxname.SelectionChanged += (ss,ee) { string comboBoxValue = comboboxname.Text; labelname.Content = comboBoxValue;}
}
Labelname being the name of the Label you want to set. In that loop you will need to implement a way of giving each box a unique name and getting the name of the associated label in there as well. That you will have to figure out on your own as i do not know how and what exactly is generated and what is static.
You will also need to add your dynamically created combobox to your listpanel or grid or whatever you are using. This works like this:
listpanelname.Children.Add(comboboxname);
Just add that to the "for" loop.
currently I have a combobox with three hard coded items.
Each item carries 2 values. I'm using a switch case statement to get the values for each item depending on which item is selected.
Switch(combobox.selectedindex)
{
case 0: // Item 1 in combobox
a = 100;
b = 0.1;
break;
case 1: // Item 2 in combobox
a = 300;
b = 0.5;
break;
//and so on....
}
I'm trying to add a feature to allow the user to add more items into the combobox with inputted a and b values. How would i be able to dynamically add case statements and define the values under each case condition? I've had a look at using a datatable instead but I don't know how to get multiple valuemembers out of the datatable when one item is selected.
Also, I would like to save the user added items and it's corresponding values to a .dat file. So when the program is re-opened it will be able to load the list of items added by the user from the file. I considered using streamwriter and readline for this but I'm unsure how it would be done.
You can use Binding on a combobox using the DataSource. The ComboBox can also be bound to other things than Primitive values (string/int/hardcoded values). So you could make a small class that represents the values you are setting in your switch statement, and then use the DisplayMember to say which property should be visible in the combobox.
An example of such a basic class could be
public class DataStructure
{
public double A { get; set; }
public int B { get; set; }
public string Title { get; set; }
}
Since you are talking about users adding values to the combobox dynamically, you could use a BindingList that contains the separate classes, this BindingList could be a protected field inside your class, to which you add the new DataStructure when the user adds one, and then automatically updates the combobox with the new value you added.
The setup of the ComboBox, can be done in either Form_Load, or in the Form Constructor (after the InitializeComponent() call), like such:
// your form
public partial class Form1 : Form
{
// the property contains all the items that will be shown in the combobox
protected IList<DataStructure> dataItems = new BindingList<DataStructure>();
// a way to keep the selected reference that you do not always have to ask the combobox, gets updated on selection changed events
protected DataStructure selectedDataStructure = null;
public Form1()
{
InitializeComponent();
// create your default values here
dataItems.Add(new DataStructure { A = 0.5, B = 100, Title = "Some value" });
dataItems.Add(new DataStructure { A = 0.75, B = 100, Title = "More value" });
dataItems.Add(new DataStructure { A = 0.95, B = 100, Title = "Even more value" });
// assign the dataitems to the combobox datasource
comboBox1.DataSource = dataItems;
// Say what the combobox should show in the dropdown
comboBox1.DisplayMember = "Title";
// set it to list only, no typing
comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
// register to the event that triggers each time the selection changes
comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;
}
// a method to add items to the dataItems (and automatically to the ComboBox thanks to the BindingContext)
private void Add(double a, int b, string title)
{
dataItems.Add(new DataStructure { A = a, B = b, Title = title });
}
// when the value changes, update the selectedDataStructure field
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox combo = sender as ComboBox;
if (combo == null)
{
return;
}
selectedDataStructure = combo.SelectedItem as DataStructure;
if (selectedDataStructure == null)
{
MessageBox.Show("You didn't select anything at the moment");
}
else
{
MessageBox.Show(string.Format("You currently selected {0} with A = {1:n2}, B = {2}", selectedDataStructure.Title, selectedDataStructure.A, selectedDataStructure.B));
}
}
// to add items on button click
private void AddComboBoxItemButton_Click(object sender, EventArgs e)
{
string title = textBox1.Text;
if (string.IsNullOrWhiteSpace(title))
{
MessageBox.Show("A title is required!");
return;
}
Random random = new Random();
double a = random.NextDouble();
int b = random.Next();
Add(a, b, title);
textBox1.Text = string.Empty;
}
}
Like this, you have the selected item always at hand, you can request the values from the properties of the selected, and you don't have to worry about syncing the ComboBox with the items currently visible
From the documentation:
Although the ComboBox is typically used to display text items, you can add any object to the ComboBox. Typically, the representation of an object in the ComboBox is the string returned by that object's ToString method. If you want to have a member of the object displayed instead, choose the member that will be displayed by setting the DisplayMember property to the name of the appropriate member. You can also choose a member of the object that will represent the value returned by the object by setting the ValueMember property. For more information, see ListControl.
So you can just add objects that hold all the information, directly to the Items collection of the ComboBox. Later, retrieve the SelectedItem property and cast it back to the correct type.
I have a List which has 16 Dictionary items, I want to assign the values of this 16 dictionaries into 16 different text fields. What I am doing now is this
txtAccountType.Text = SheetData[0]["KeyName"].ToString();
txtAccountName.Text = SheetData[1]["KeyName"].ToString();
txtAccountAddress.Text = SheetData[2]["KeyName"].ToString();
txtAccountActivationDate.Text = SheetData[3]["KeyName"].ToString();
txtAccountExpiry.Text = SheetData[4]["KeyName"].ToString();
SheetData is a instance of List class containing multiple dictionaries.
I thought of using the for loop as well but the problem is that it did not work because every time I used to see the last dictionaries value in all the text fields.
The above solution works fine for me but what if I get 15 dictionaries or 10 dictionaries in future, the solution I am using is not dynamic here so could you please suggest me on how can I improve this.
Its not possible to decide which data to assign for particular textbox. If any data can be assigned to any of the text box below code will work for you. It works like first element will be assigned to first textbox.
int i = 0;
foreach (Control ctl in controls)
{
if (ctl is TextBox)
{
TextBox txt = (TextBox)ctl;
txt.Text = SheetData[i]["KeyName"].ToString();
i++;
}
}
Here controls are the collection of ControlCollection object. For example you can collect it from form like this ControlCollection controls = this.form1.Controls;
Is it possible, to bind (or similar) a standard textbox to display the contents (dynamically) of the selected cell within a datagridview textboxcolumn?
My goal is that when a cell within this column has it's value altered, the textbox.text is also changed, and when the user selects a cell then types something in this separate textbox the value is updating the datagridview textboxcolumns value on the fly.
Yes you may bind common dataSource to both TextBox and DataGridView.
public class Foo
{
public string Item { get; set; }
}
private void Form2_Load(object sender, EventArgs e)
{
List<Foo> list = new List<Foo>()
{
new Foo() { Item="1" },
new Foo() { Item="2" }
};
dataGridView1.DataSource = list;
textBox1.DataBindings.Add("Text", list, "Item");
}
Applying the idea from "adatapost" to a DataGridView in C#:
TextBox txt = this.txtBox1;
DataGridView dgv = this.datagridview1;
txt.DataBindings.Add("Text", dgv.DataSource, "FieldName");
dgv = null;
txt = null;
It might not be necessary to declare separate variables to hold your TextBox and DataGridView while you create the Binding. I just show these for clarity, in fact, this would be sufficient:
this.txtBox1.DataBindings.Add("Text", this.datagridview1.DataSource, "FieldName"
To clarify, "Text" means output the value back to the "Text" property of the TextBox, and "FieldName" should be replaced with whatever the column is in your DataGridView that you want to bind to.
Note - make sure that you have already set the DataSource / populated the DataGridView before you put the Binding code, if the DataSource is not set and therefore containing the field that you wish to bind to you will get an error.
I'm having trouble figuring out how to add items to a ListBox in WinForms.
I have tried:
list.DisplayMember = "clan";
list.ValueMember = sifOsoba;
How can I add ValueMember to the list with an int value and some text for the DisplayMember?
list.Items.add(?)
Btw. I can't use ListBoxItem for any reasons.
ListBoxItem is a WPF class, NOT a WinForms class.
For WPF, use ListBoxItem.
For WinForms, the item is a Object type, so use one of these:
1. Provide your own ToString() method for the Object type.
2. Use databinding with DisplayMemeber and ValueMember (see Kelsey's answer)
list.Items.add(new ListBoxItem("name", "value"));
The internal (default) data structure of the ListBox is the ListBoxItem.
In WinForms, ValueMember and DisplayMember are used when data-binding the list. If you're not data-binding, then you can add any arbitrary object as a ListItem.
The catch to that is that, in order to display the item, ToString() will be called on it. Thus, it is highly recommended that you only add objects to the ListBox where calling ToString() will result in meaningful output.
You might want to checkout this SO question:
C# - WinForms - What is the proper way to load up a ListBox?
DisplayMember and ValueMember are mostly only useful if you're databinding to objects that have those properties defined. You would then need to add an instance of that object.
e.g.:
public class MyObject
{
public string clan { get; set; }
public int sifOsoba { get; set; }
public MyObject(string aClan, int aSif0soba)
{
this.clan = aClan;
this.sif0soba = aSif0soba;
}
public override string ToString() { return this.clan; }
}
....
list.Items.Add(new MyObject("hello", 5));
If you're binding it manually then you can use the example provided by goggles
The way I do this - using the format Event
MyClass c = new MyClass();
listBox1.Items.Add(c);
private void listBox1_Format(object sender, ListControlConvertEventArgs e)
{
if(e.ListItem is MyClass)
{
e.Value = ((MyClass)e.ListItem).ToString();
}
else
{
e.Value = "Unknown item added";
}
}
e.Value being the Display Text
Then you can attempt to cast the SelectedItem to MyClass to get access to anything you had in there.
Also note, you can use anything (that inherits from object anyway(which is pretty much everything)) in the Items Collection.
If you just want to add a string to it, the simple answer is:
ListBox.Items.Add("some text");
You have to create an item of type ListBoxItem and add that to the Items collection:
list.Items.add( new ListBoxItem("clan", "sifOsoba"));
If you are adding integers, as you say in your question, this will add 50 (from 1 to 50):
for (int x = 1; x <= 50; x++)
{
list.Items.Add(x);
}
You do not need to set DisplayMember and ValueMember unless you are adding objects that have specific properties that you want to display to the user. In your example:
listbox1.Items.Add(new { clan = "Foo", sifOsoba = 1234 });