Using Loops in ComboBox Items in another Method - c#

I. This is the part of the code in the C# form
this.cbDay.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.cbDay.FormattingEnabled = true;
this.cbDay.Items.AddRange(new object[] {
});//items from a loop in another class and method.
II. This is my method in another class
namespace StudentRegistrationApplication
public class loopComboBoxSelection
{
public loopComboBox(int start, int finsh)
{
for (int i = start; i < finsh; i++)
{
ComboboxItem item = new ComboboxItem();
item.Text = "Item " + i;
item.Value = i;
ModDown.Items.Add(item);
}
}
}
III. I want to call the loop method that will generate items from 1 to 100. For this question, what is the syntax?
this.cbDay.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.cbDay.FormattingEnabled = true;
this.cbDay.Items.AddRange(new object[] {
"1"
"2"
"3"
"4"
"5"});

You're doing it wrong. You should be binding the data to the ComboBox, e.g.
cbDay.DisplayMember = nameof(ComboBoxItem.Text);
cbDay.ValueMember = nameof(ComboBoxItem.Value);
cbDay.DataSource = Enumerable.Range(startValue, endValue - startValue + 1)
.Select(i => new ComboBoxItem {Text = $"Item {i}", Value = i})
.ToArray();
The Text values will then be displayed in the control and, when the user makes a selection, you can get the corresponding Value from the SelectedValue property of the control.
Note that you don't have to use LINQ to create the list but it's the binding part that's important. By setting the DataSource, you're able to get a specific property value from the SelectedValue rather than just the same as you'd get from SelectedItem.

Related

Datagridview with comboboxes referencing to the own dataset mixing rows

I have a DataGridView which is based on a DataSet from a data base referenced by a BindingSource. In the DataSet there is an ID as primary key. Further there is another field in the DataSet containing an BuddyID referencing to another row of the same table. And a field containing a name of the element.
In the DataGridView there is the DataGridViewTextboxColumn with the name and DataGridViewComboboxColumn where you can select the Name of another element to change the BuddyID, reverencing by another BindingSource to the same DataSet. But that don't work like I would have it.
When you have two elements as buddy to each other and you want to set the IDs, then the BuddyID of the other element is changed to the same value too. Although I don't change the other ComboBox the value is changing! Maybe it's a problem of the combo box, but I have no idea about what to do to fix that. Maybe anyone of yours?
Edit: both (buddy) elements have the same name appearing in the combo box
Code generated by the designer - unluckily with name "text" instead of "combo":
private System.Windows.Forms.DataGridViewComboBoxColumn idBuddyDataGridViewTextBoxColumn;
private System.Windows.Forms.DataGridViewComboBoxColumn idB uddyDataGridViewTextBoxColumn;
//
// idBuddyDataGridViewTextBoxColumn
//
this.idBuddyDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.idBuddyDataGridViewTextBoxColumn.DataPropertyName = "IdBuddy";
this.idBuddyDataGridViewTextBoxColumn.DataSource = this.komponentenBuddyBindingSource;
this.idBuddyDataGridViewTextBoxColumn.DisplayMember = "Komponentenname";
this.idBuddyDataGridViewTextBoxColumn.HeaderText = "Buddy";
this.idBuddyDataGridViewTextBoxColumn.Name = "idBuddyDataGridViewTextBoxColumn";
this.idBuddyDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True;
this.idBuddyDataGridViewTextBoxColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
this.idBuddyDataGridViewTextBoxColumn.ValueMember = "Id";
this.idBuddyDataGridViewTextBoxColumn.Width = 62;
Code for the DataGridView by designer:
private System.Windows.Forms.DataGridView dgvKomponenten;
this.dgvKomponenten = new System.Windows.Forms.DataGridView();
((System.ComponentModel.ISupportInitialize)(this.dgvKomponenten)).BeginInit();
//
// dgvKomponenten
//
this.dgvKomponenten.AllowUserToDeleteRows = false;
this.dgvKomponenten.AutoGenerateColumns = false;
this.dgvKomponenten.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dgvKomponenten.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.komponentennameDataGridViewTextBoxColumn,
... (10 other columns) ...
this.idBuddyDataGridViewTextBoxColumn});
this.dgvKomponenten.DataSource = this.komponentenBindingSource;
this.dgvKomponenten.Dock = System.Windows.Forms.DockStyle.Fill;
this.dgvKomponenten.Location = new System.Drawing.Point(0, 0);
this.dgvKomponenten.Name = "dgvKomponenten";
this.dgvKomponenten.Size = new System.Drawing.Size(452, 612);
this.dgvKomponenten.TabIndex = 9;
this.dgvKomponenten.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(this.dgvKomponenten_CellValueChanged);
this.dgvKomponenten.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(this.dgvKomponenten_DataError);
this.dgvKomponenten.RowEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dgvKomponenten_RowEnter);
((System.ComponentModel.ISupportInitialize)(this.dgvKomponenten)).EndInit();
And some called code by myself:
private void dgvKomponenten_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgvChanged = ((DataGridView)sender);
FilteredTypeDataGridViewComboBoxCell ftdgvcbcSubtyp;
if (null != dgvChanged.Columns["idTypDataGridViewTextBoxColumn"])
{
if (e.ColumnIndex == dgvChanged.Columns["idTypDataGridViewTextBoxColumn"].Index)
{
ftdgvcbcSubtyp = (FilteredTypeDataGridViewComboBoxCell)dgvChanged.Rows[e.RowIndex].Cells["idSubtypDataGridViewTextBoxColumn"];
ftdgvcbcSubtyp.InitCellFilter(e.RowIndex);
if (!ftdgvcbcSubtyp.Items.Contains(ftdgvcbcSubtyp.Value))
{
ftdgvcbcSubtyp.Value = 0;
}
}
}
}
You're right; it appears the combo used in the DGV has a bug where it case insensitively looks up the chosen item based on the display text.. If you have 5,"John" or even 5,"john" you can never select it, because choosing it always finds/sets the selection to the first John (the one with id 1)
This is the best workaround I've been able to come up with:
public class Buddy {
public string Name { get; set; }
public int Id { get; set; }
}
public Form1(string s1 = null)
{
InitializeComponent();
dataSet1.People.AddPeopleRow(1, "John", 1);
dataSet1.People.AddPeopleRow(2, "Mary", 1);
dataSet1.People.AddPeopleRow(3, "Mark", 1);
dataSet1.People.AddPeopleRow(4, "Luke", 1);
dataSet1.People.AddPeopleRow(5, "John", 1);
var b = new BindingList<Buddy>();
var h = new Dictionary<string, int>();
foreach (var r in dataSet1.People)
{
if (!d.TryGetValue(r.Name.ToLower(), out int x))
x = 0;
b.Add(new Buddy { Name = r.Name + (x > 0 ? new string('\0', x) : ""), Id = r.Id });
d[r.Name.ToLower()] = x + 1;
}
buddyBindingSource.DataSource = b;
peopleBindingSource.DataSource = dataSet1.People;
}
Namely, we zip through the list of people building a new list of name/id pairs to show in our combo. Every time we hit a name we've seen before, we add an increasing number of NUL characters onto the end of the name. They don't show in the combo, but they permit the text to be different, so that selecting the 5th John really does select that one, not the first one.

Set Combobox selected item based on its ItemsValue

I have a Combobox, in which let's say that an item's Display Text is "School" and it's Item Value is 19. So i have stored this 19 into a DataGrid.
Then, i retrieve Combobox Value from DataGrid, then what i want to do is simply that based on value retrieved from DataGrid, combobox should set it's display Item or SelectedItem which have Value 19. In above scenario Combobox should display its selected item "School" if its value was 19.
So far i have wrote code upto this point. But it always giving me First Item of a Combobx.
DataGrid gd = (DataGrid)sender;
DataRowView rowSelected = gd.SelectedItem as DataRowView;
if(rowSelected!=null)
{
for (int i = 0; i < comboBox1.Items.Count;i++ )
{
if (Convert.ToString(comboBox1.SelectedValue) == Convert.ToString(rowSelected[14]))
{
index = comboBox1.Items.IndexOf(comboBox1.SelectedValue);
}
comboBox1.SelectedItem= comboBox1.Items[index];
}
textBox9.Text=rowSelected[14].ToString();
}
Now i am able to retrieve the Combobox Item, Based on its value which i am retrieving from the WPF DataGrid.
for (int i = 0;i <comboBox1.Items.Count; i++)
{
comboBox1.SelectedIndex = i;
if ((string)(comboBox1.SelectedValue) == Convert.ToString(rowSelected[14]))
{
index = i;
}
}
comboBox1.SelectedIndex = index;
Change your code to
if(rowSelected!=null)
{
int index = comboBox1.Items.IndexOf(rowSelected[14]);
comboBox1.SelectedItem = comboBox1.Items[index];
}
or
Use FindStringExact() method of combobox
int i = comboBox1.FindStringExact("Combo");
if(i >= 0)
{
}

How to bind ComboBox value to the TextBox value

I want to bind the ComboBox value upto the TextBox value. Here is an example:
Let's say I have one TextBox and one ComboBox
Now in TextBox there is value of 5. So as per the TextBox value is 5 my ComboBox would be bind upto 5 and in the list of ComboBox it would be saw the number upto 5 i.e. 1,2,3,4,5.
Same if the TextBox contain the value 3 then as per the change of TextBox value on the spot ComboBox should be bind upto the TextBox value.
I am working on it also but there is some list error.
Here is my code:
List<string> hafta = new List<string>();
hafta.Add(txt_hafta.Text);
for (int i = 0; i <= hafta.Count; i++)
{
cmb_hafta.BindingContext = this.BindingContext;
cmb_hafta.DataSource = hafta[i];
cmb_hafta.DisplayMember = i.ToString();
}
I am not sure that this code is perfect.
On TextBox text changed:
int count = 0;
Int32.TryParse(txt_hafta.Text, out count);
List<int> dataSource = new List<int>();
for (int i = 1; i <= count; i++)
{
dataSource.Add(i);
}
hafta.DataSource = dataSource;
hafta.DropDownStyle = ComboBoxStyle.DropDownList
If you talk about binding, then you can bind ComboBox.DataSource property to TextBox.Text property with custom eventhandler for Binding.Format event, where you can "convert" string to collection of numbers.
Put code below in the constructor of your form.
var binding =
new Binding("DataSource", txt_hafta, "Text", true, DataSourceUpdateMode.Never);
binding.Format += (sender, args) =>
{
int.TryParse(args.Value.ToString(), out int maxNumber);
args.Value = Enumerable.Range(1, maxNumber).ToList();
};
cmb_hafta.DataBindings.Add(binding);
You can do something like this:
List<string> hafta = new List<string>();
int total = Int32.Parse(txt_hafta.Text);
for (int i = 0; i <= total ; i++)
{
hafta.Add(i.ToString());
}
cmb_hafta.DataSource = hafta;

Filling a dictionary with numbers from textbox and with the textboxes as keys

I'm writing a code where I want to get the numbers from multiple TextBox controls into a collection. Sort it, then change the background color of the textboxes containing the top 3 highest value. This is the dictionary
Dictionary<System.Windows.Forms.TextBox, string> all_cycles = new Dictionary<System.Windows.Forms.TextBox, string>(10);
for (var i = 1; i < 5; i++)
{
all_cycles.Add(((System.Windows.Forms.TextBox)this.Controls.Find("txtendc" + Convert.ToString(i), true)[0]),this.Text);
}
I know that with "this.text" I won't get the textboxes values so that's why I'm asking.
I also tried creating an array which only contains the values of the textboxes which I then use to fill the dictionary. But it always drops an Index was outside the bounds of the array. Or Index was out of range exception. This drops the out of range exception:
List<System.Windows.Forms.TextBox> txtendc = new List<System.Windows.Forms.TextBox>(10);
for (var i = 1; i < 5; i++)
{
txtendc.Add((System.Windows.Forms.TextBox)this.Controls.Find("txtendc" + Convert.ToString(i), true)[0]);
}
int[] endc_content = new int[10];
for (var i = 1;i < 5; i++)
{
endc_content[i]= int.Parse(txtendc[i].Text);
}
I don't have any problem with the coloring, just filling up the dictionary. If you have a better solution than the dictionary collection please tell me.
Thanks
EDIT: This whole code is inside a timer tick event if it matters anything
I would create a list of all of your TextBoxes in code behind when you instantiate your class. Then you could use Linq to get the top 3. Remember that you will need to confirm that all of the textboxes actually contain numbers - ensure that your program doesn't crash if you enter text into one of them. If all of the TextBoxes in the form will be holding these numbers, you could do something like this to validate and sort in one method (not tested):
private List<TextBox> myTextBoxes { get; set; }
public Form1()
{
InitializeComponent();
foreach (Control c in this.Controls)
{
if (c.GetType() == typeof(TextBox))
myTextBoxes.Add((TextBox)c);
}
}
private IEnumerable<TextBox> getTop3()
{
return myTextBoxes.Where(tb => tb.Text.AsEnumerable().All(char.IsDigit)).Select(tb => tb).OrderByDescending(tb => Double.Parse(tb.Text)).Take(3);
}
The first step of the Linq query converts the text to an enumerable of char and ensures that all characters contain digits (instead of letters). The second selects these textboxes. The third parses them into doubles and compares them, highest number first. The last takes the first three in the list (the textboxes containing the highest 3 numbers)
EDIT: Based on your comments, the code could be simplified to:
public Form1()
{
InitializeComponent();
}
private IEnumerable<TextBox> getTop3(string textboxPrefix)
{
List<TextBox> textBoxesToSort = new List<TextBox>();
foreach (Control c in this.Controls)
if (c.GetType() == typeof(TextBox) && c.Name.StartsWith(textboxPrefix))
textBoxesToSort.Add((TextBox)c);
return textBoxesToSort.OrderByDescending(tb => Double.Parse(tb.Text)).Take(3);
}
You can sort those TextBox controls based on values and then select top 3 from the list:
var result = this.Controls.OfType<TextBox>().Select(x =>
{
try { return new { Key = x, Value = Convert.ToInt32(x.Text) }; }
catch { return null; }
})
.Where(x=>x!=null)
.OrderByDescending(x => x.Value)
.Take(3)
.ToDictionary(x => x.Key, x => x.Value);
To test the result, show a message box containing values:
MessageBox.Show(string.Join("\n",
result.Select((x, i) => string.Format("{0}:{1}", i+1, x.Value))));
Above example will be applied on any list of TextBox controls and just for example I used all TextBox controls of the form.
Please try this, hope it helps:
List<System.Windows.Forms.TextBox> all_cycles = new List<System.Windows.Forms.TextBox>(10);
int[] indexOfTextBox = new int[3];
foreach(var cycle in all_cycles)
{
int value = Convert.ToInt16(cycle.Text);
if (value > indexOfTextBox[0])
{
indexOfTextBox[0] = value;
}
else if (value > indexOfTextBox[1])
{
indexOfTextBox[1] = value;
}
else if (value > indexOfTextBox[2])
{
indexOfTextBox[2] = value;
}
}
all_cycles[indexOfTextBox[0]].BackColor = ConsoleColor.Red;
all_cycles[indexOfTextBox[1]].BackColor = ConsoleColor.Blue;
all_cycles[indexOfTextBox[2]].BackColor = ConsoleColor.Green;

Why when adding items to combobox it's adding the same item many times?

In the top of form1:
public class ComboboxItem
{
public string Text { get; set; }
public object Value { get; set; }
public override string ToString()
{
return Text;
}
}
List<string> results = new List<string>();
Then:
ComboboxItem item = new ComboboxItem();
var result = videoCatagories.Execute();
for (int i = 0; i < result.Items.Count; i++)
{
item.Text = result.Items[i].Snippet.Title;
item.Value = result.Items[i].Id;
comboBox1.Items.Add(item);
}
And in the end:
private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
MessageBox.Show((comboBox1.SelectedItem as ComboboxItem).Value.ToString());
}
What i wanted to do in general is to add to the combobox the titles and then when i select a title to get the title id.
For example i run the program and select the title Weather now i want to see in a messageBow.Show the id 1
There are 31 items.
When i use a breakpoint and look on result i see 31 items when i click on the first item in index 0 i see Id = "1" and then i click on snippet and see title "weather"
Then i do the same for item in index 1 and i see Id = "19" and in the snippet the title is "animals".
But for some reason it's adding each itertion the same item many times.
Create a new instance of ComboboxItem each time you want to add a new item to the combo box:
for (int i = 0; i < result.Items.Count; i++)
{
ComboboxItem item = new ComboboxItem();
item.Text = result.Items[i].Snippet.Title;
item.Value = result.Items[i].Id;
comboBox1.Items.Add(item);
}
Your code changes the properties of the same item instance for each entry in results, then adds it to the comboBox1.Items collection. Add inserts its argument to the Items collection, it doesn't copy its contents. As a result, when the combobox is rendered, all combobox items point to the same item. To avoid this, create a new item instance for each entry in results:
for (int i = 0; i < result.Items.Count; i++)
{
var item=new ComboboxItem
{
Text = result.Items[i].Snippet.Title,
Value = result.Items[i].Id
};
comboBox1.Items.Add(item);
}
or
var items=from item in result
select new ComboboxItem
{
Text = item.Snippet.Title,
Value = item.Id
};
comboBox1.Items.AddRange(items);
You could do a simple check to make sure that the combobox doesn't already contain it before doing the insert.
ComboboxItem item = new ComboboxItem();
var result = videoCatagories.Execute();
for (int i = 0; i < result.Items.Count - 1; i++)
{
if(!comboBox1.Items.Contains(item))
{
item.Text = result.Items[i].Snippet.Title;
item.Value = result.Items[i].Id;
comboBox1.Items.Add(item);
}
}
Or you can do like this article suggests and remove every item that is the same before adding the new item to remove conflicts, No Duplicate in a Listbox or using the same way to stop duplicates from a combobox too

Categories

Resources