I have a combobox , bound to Datatable
and have the following properties:
cboCars.DisplayMember = "carLiscen";
cboCars.ValueMember = "carNo";
How can I select the DisplayMember when I know the ValueMember ?
If you have a ValueMember set you can select using SelectedValue
cboCars.DisplayMember = "carLiscen";
cboCars.ValueMember = "carNo";
cboCars.SelectedValue = "valuemember value";
You can use cboCars.SelectedValue = "123"; property for this. Here's a code snippet which will show it in action.
public void Test()
{
ArrayList info = new ArrayList();
info.Add(new CarInfo { CarLiscen = 123456, CarNo = 123});
info.Add(new CarInfo { CarLiscen = 234567, CarNo = 234 });
cboCars.DataSource = info;
cboCars.DisplayMember = "CarLiscen";
cboCars.ValueMember = "CarNo";
cboCars.SelectedValueChanged +=
delegate(object sender, EventArgs e)
{
if (cboCars.SelectedIndex != -1)
{
this.Text = cboCars.SelectedValue.ToString();
}
};
cboCars.SelectedValue = 234;
}
And if you wonder what is the definition of CarInfo. Here's its code (which is fairly simple):
public class CarInfo
{
public int CarLiscen { get; set; }
public int CarNo { get; set; }
}
Hope this helps.
You can search for the correct item and set it to that, very simple:
cbTEST.SelectedIndex = cbTEST.FindStringExact("your search string here");
or select an item based on an ListViewItem:
cbTEST.SelectedIndex = cbTEST.FindStringExact(lvTEST.SelectedItems[0].SubItems[0].Text);
thats it. very simple!
Hi Guys the best way if searching for a text or value
is
int Selected;
int count = ComboBox1.Items.Count;
for (int i = 0; (i<= (count - 1)); i++)
{
ComboBox1.SelectedIndex = i;
if ((string)(ComboBox1.SelectedValue) == "SearchValue")
{
Selected = i;
}
}
ComboBox1.SelectedIndex = Selected;
The problem is that the combobox expect the exact type.
So if you for example use a datagridview and you see the value (int) in the field, you pass it to the SelectedValue property of the combo. But in fact you are not passing an integer, you are passing an object. That is what usually is going wrong. It my a while to sort this out, but finally I have found how to do it...
How to solve this... easy:
For example, you have an ID (integer in the database), then you need to do something like this:
This is the one that I did and it does not work:
cmbFilter.SelectedValue = dgvListOfFilters.Rows[intRowSelected].Cells[3].Value;
You should do this to make it work:
int intCategory = Convert.ToInt32(dgvListOfFilters.Rows[intRowSelected].Cells[3].Value);
cmbFilter.SelectedValue = intCategory;
Hope this will be helpfull for many people...
Related
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.
I have done the following code and works well. I am wondering how I can do a for loop to clean this code from 38 lines into 2 lines.
s0s.Text = seg[0].start.ToString("X8");
s0e.Text = seg[0].end.ToString("X8");
s1s.Text = seg[1].start.ToString("X8");
s1e.Text = seg[1].end.ToString("X8");
// .. many more ..
s19s.Text = seg[19].start.ToString("X8");
s19e.Text = seg[19].end.ToString("X8");
I can obviously do the seg[i] substitution, but how do i do it with the text boxes?
I suppose you could use the Controls property and call OfType<T>() to get all the instances of TextBoxes in your Form instance
Filters the elements of an IEnumerable based on a specified type.
Then convert the results to a Dictionary based on the control Name
// this could potentially be done in the constructor
var dict = Controls.OfType<TextBox>().ToDictionary(x => x.Name);
for (int i = 0; i < 19; i++)
{
dict[$"s{i}s"].Text = $"{seg[i].Start:X8}";
dict[$"s{i}e"].Text = $"{seg[i].End:X8}";
}
Note : This code is untested and only a guide to a possible solution
I'd be tempted to do it this way. First create two lists of your controls, the starts and the ends:
var starts = new List<TextBox>
{
s0s,
s1s,
//...
s19s
};
var ends = new List<TextBox>
{
s0e,
s1e,
//...
s19e
};
Then loop over each list:
var i = 0;
foreach (var start in starts)
{
start.Text = seg[i].start.ToString("X8");
++i;
}
i = 0;
foreach (var end in ends)
{
start.Text = seg[i].end.ToString("X8");
++i;
}
Your indexes and control numbers would need to line up perfectly though.
Note: Like TheGeneral's code, this is untested (neither of us wants to create a form with 38 text boxes with specific names)
Based on the textboxes names I would suggest alternative approach to use control designed to display collection of things - DataGridView would be one of the options.
With data binding you can achieve little bit more maintainable code
public class MyItem
{
public int Start { get; set; }
public int End { get; set; }
}
In the form create a datagridview with two bounded columns, you can do this in winforms designer without manually writing the code below.
// constructor
public MyForm()
{
var startColumn = new DataGridViewTextBoxColumn();
startColumn.DataPropertyName = "Start"; // Name of the property in MyItem class
startColumn.DefaultCellStyle.Format = "X8";
var endColumn = new DataGridViewTextBoxColumn();
endColumn.DataPropertyName = "End"; // Name of the property in MyItem class
endColumn.DefaultCellStyle.Format = "X8";
myDataGridView.Columns.AddRange(startColumn, endColumn);
myDataGridView.AutoGenerateColumns = false;
}
private void Form1_Load(object sender, EventArgs e)
{
var items = new List<MyItem>
{
new MyItem { Start = 10, End = 20 },
new MyItem { Start = 11, End = 19 },
new MyItem { Start = 12, End = 18 }
};
myDataGridView.DataSource = items;
}
firstly when you create they variables insert them all to an array. then run a loop as following:
for (int i; int < 19(your list); i++)
{
your list[i].Text = seg[i].start.ToString("X8");
your list[i].Text = seg[i].end.ToString("X8");
}
So I have an array, strArray, that stores the values of my text files which has 3 columns. I think this is called a two or three dimensional array, not sure. Or maybe one dimensional. I have a List<> called Inventory which adds the data to it.
I currently have three successful columns I just need the fourth. The fourth column is the second and third column multiplied together, which is a total price. The second column is an int, "Number of Items", the third is a decimal, "Price" and the fourth is a decimal, "Total Price" which is Number of Items * Price.
I'll go ahead and post my code, I am also using four list boxes for the data. Three columns (or three list boxes) work fine, but I just gotta get the fourth one figured out.
Sorry for the large amount of code, I figured if I copied all of it it'll make it easier to see if an error occurred earlier on. btnLoadInfo_Click is the event/method where the main issue is.
namespace TCSCapstone
{
public partial class frmInventory : Form
{
List<frmInventory> Inventory = new List<frmInventory>();
public frmInventory()
{
InitializeComponent();
}
public string ItemName { get; set; }
public int NumberOfItems { get; set; }
public decimal Price { get; set; }
public decimal TotalPrice { get; set; }
string selectedList = "";
private void cmbList_SelectedIndexChanged(object sender, EventArgs e)
{
selectedList = this.cmbList.GetItemText(this.cmbList.SelectedItem);
lstItemName.DataSource = null;
lstNumberOfItems.DataSource = null;
lstPrice.DataSource = null;
lstItemName.Items.Clear();
lstNumberOfItems.Items.Clear();
lstPrice.Items.Clear();
lstTotalPrices.Items.Clear();
if (selectedList == "Creative Construction")//if the selected combo box item equals the exact string selected
{
selectedList = "creative"; //then the string equals creative, which is creative.txt but I add the .txt in the btnLoadInfo method
} else if (selectedList == "Paradise Building")
{
selectedList = "paradise";//this is for paradise.txt
}
else if (selectedList == "Sitler Construction")
{
selectedList = "sitler";//this is for sitler.txt
}
else
{
MessageBox.Show("Please select one of the items.");
}
}`
private void btnLoadInfo_Click(object sender, EventArgs e)
{
Inventory.Clear(); //Clears the entire Inventory List
using (StreamReader invReader = new StreamReader(selectedList +
".txt"))
{
while (invReader.Peek() >= 0)
{
string str;
string[] strArray;
str = invReader.ReadLine();
strArray = str.Split(',');
frmInventory currentItem = new frmInventory();
currentItem.ItemName = strArray[0];
currentItem.NumberOfItems = int.Parse(strArray[1]);
currentItem.Price =
decimal.Parse(strArray[2]);
strArray[1].
currentItem.TotalPrice = decimal.Parse(strArray[1] *
strArray[2]);
Inventory.Add(currentItem);
}
}
displayLists(); //Calls the displayLists method to update list
//boxes at the end of the button click event
}//end of btnLoadInfo
void displayLists()
{
//Resets the listboxes datasources by setting them to null
lstItemName.DataSource = null;
lstNumberOfItems.DataSource = null;
lstPrice.DataSource = null;
lstItemName.Items.Clear();
lstNumberOfItems.Items.Clear();
lstPrice.Items.Clear();
lstTotalPrices.Items.Clear();
lstItemName.DisplayMember = "ItemName";
lstItemName.ValueMember = "";
lstItemName.DataSource = Inventory;
lstNumberOfItems.DisplayMember = "NumberOfItems";
lstNumberOfItems.ValueMember = "";
lstNumberOfItems.DataSource = Inventory;
lstPrice.DisplayMember = "Price";
lstPrice.ValueMember = "";
lstPrice.DataSource = Inventory;
}
Your TotalPrice property should be a mathematical equation, not something you set independently of the number of items and their prices.
Change the property to this:
public decimal TotalPrice{
get{ return NumberOfItems * Price; }
}
Delete the line that sets TotalPrice in your loop; it's no longer necessary because you've set the item price and the number of items; the total price inherently follows from these
You're trying to multiply two strings together. Instead, multiply the numeric values that you have already parsed:
currentItem.TotalPrice = currentItem.NumberOfItems * currentItem.Price;
I have a listbox displaying items from an enum. I want to select/highlight the current value (read from a database) when the listbox displays/the form opens. This code, though:
lblSelectedPrinter.Text = AppSettings.ReadSettingsVal("beltprinter");
listBoxBeltPrinters.SelectedItem = listBoxBeltPrinters.Items.IndexOf(lblSelectedPrinter.Text);
...does not work. I saw an example using "GetItemAt" here (Programmatically selecting Items/Indexes in a ListBox) but my stripped down and archaic version of C# (.NET 1.1, C# 2) has no such critter.
UPDATE
I thought this would work:
string currentPrinter = AppSettings.ReadSettingsVal("beltprinter");
lblSelectedPrinter.Text = currentPrinter;
int currentPrinterIndex = listBoxBeltPrinters.Items.IndexOf(currentPrinter);
listBoxBeltPrinters.SelectedItem = currentPrinterIndex;
...but it, also, does not (the current printer displays in the label, but the corresponding entry/value in the listbox is not selected).
I see you've already solved this, but why not do it the tried and tested way?
lblSelectedPrinter.Text = AppSettings.ReadSettingsVal("beltprinter");
listBoxBeltPrinters.SelectedIndex = -1;
if (!String.IsNullOrEmpty(lblSelectedPrinter.Text)) {
for (int index = 0; index < listBoxBeltPrinters.Items.Count; index++) {
string item = listBoxBeltPrinters.Items[index].ToString();
if (lblSelectedPrinter.Text == item) {
listBoxBeltPrinters.SelectedItem = index;
break;
}
}
}
This way, you know the SelectedIndex value is set to -1 as soon as the text changes, and if it is found in your ListBox, that item is selected.
Even better would be to write a handler when the Label control lblSelectedPrinter fires the TextChanged event.
lblSelectedPrinter.TextChanged += new EventHandler(SelectedPrinter_TextChanged);
Then, create that Event Handler like shown above:
private void SelectedPrinter_TextChanged(object sender, EventArgs e) {
listBoxBeltPrinters.SelectedIndex = -1;
if (!String.IsNullOrEmpty(lblSelectedPrinter.Text)) {
for (int index = 0; index < listBoxBeltPrinters.Items.Count; index++) {
string item = listBoxBeltPrinters.Items[index].ToString();
if (lblSelectedPrinter.Text == item) {
listBoxBeltPrinters.SelectedItem = index;
break;
}
}
}
}
You've already solved your problem, so this is just food for thought.
This works:
listBoxBeltPrinters.SetSelected(listBoxBeltPrinters.FindString("beltprinter"), true);
int i = AppSettings.ReadSettingsVal("beltprinter"); //Save it as an int.
listBoxBeltPrinters.SelectedItem = listBoxBeltPrinters.Items.IndexOf(i);
lblSelectedPrinter.Text = listBoxBeltPrinters.SelectedItem.toString();
You need it to be an integer. You can use int.Parse to Convert to cast it from string to int.
listBoxBeltPrinters.SelectedItem = listBoxBeltPrinters.Items.IndexOf(int.Parse(System.Configuration.ConfigurationSettings.AppSettings.Get("beltprinter")));
lblSelectedPrinter.Text = listBoxBeltPrinters.SelectedItem.toString();
This works:
string currentPrinter = AppSettings.ReadSettingsVal("beltprinter");
lblSelectedPrinter.Text = currentPrinter;
int currentPrinterIndex = listBoxBeltPrinters.Items.IndexOf(currentPrinter);
listBoxBeltPrinters.SelectedIndex = currentPrinterIndex;
This is the only code required to display, read, and write the settings val:
private void PrinterPickerForm_Load(object sender, System.EventArgs e)
{
Type type = typeof(PrintUtils.BeltPrinterType);
foreach (FieldInfo field in type.GetFields(BindingFlags.Static | BindingFlags.Public))
{
string display = field.GetValue(null).ToString();
listBoxBeltPrinters.Items.Add(display);
}
string currentPrinter = AppSettings.ReadSettingsVal("beltprinter");
lblCurrentPrinter.Text = currentPrinter;
int currentPrinterIndex = listBoxBeltPrinters.Items.IndexOf(currentPrinter);
listBoxBeltPrinters.SelectedIndex = currentPrinterIndex;
}
private void btnSaveSelectedVal_Click(object sender, System.EventArgs e)
{
string sel = listBoxBeltPrinters.SelectedItem.ToString();
if (sel != lblCurrentPrinter.Text)
{
AppSettings.WriteSettingsVal("beltPrinter", sel);
}
}
can you try the following??? It takes from your code, and then uses FindString
string currentPrinter = AppSettings.ReadSettingsVal("beltprinter");
lblSelectedPrinter.Text = currentPrinter;
int index = listBoxBeltPrinters.FindString(lblSelectedPrinter.Text);
listBoxBeltPrinters.SelectedIndex = index;
Combination of listBoxObject.SetSelected() and listBoxObject.FindString() is an elegant solution. It works for me, too.
lblSelectedPrinter.Text = AppSettings.ReadSettingsVal("beltprinter");
listBoxBeltPrinters.SelectedItem = listBoxBeltPrinters.Items.FindByText(lblSelectedPrinter.Text);
By value:
listBoxBeltPrinters.SelectedItem = listBoxBeltPrinters.Items.FindByValue(1);
I have a DataGridView that I'm populating from a list. The function that edits this list is called LoadCollectionData()'. Extra rows get added to the list just fine, and the relevant data pertaining to that row populates when the row is added.
The problem is that later on when other data is being changed that'd alter what's displayed on the datagrid, only the top row continues to update, all of the others remain the same.
Here's the code for the method:
public bool haschanged = false;
public class KeywordDensity
{
public bool included { get; set; }
public string keyword { get; set; }
public string occurences { get; set; }
public string density { get; set; }
}
public int WordCount(string txtToCount)
{
string pattern = "\\w+";
Regex regex = new Regex(pattern);
int CountedWords = regex.Matches(txtToCount).Count;
return CountedWords;
}
public int KeywordCount(string txtToCount, string pattern)
{
Regex regex = new Regex(pattern);
int CountedWords = regex.Matches(txtToCount).Count;
return CountedWords;
}
public List<KeywordDensity> LoadCollectionData()
{
string thearticle = txtArticle.Text.ToLower();
string keywordslower = txtKeywords.Text.ToLower();
string[] keywordsarray = keywordslower.Split('\r');
List<KeywordDensity> lsikeywords = new List<KeywordDensity>();
bool isincluded = false;
double keywordcount = 0;
double wordcount = WordCount(thearticle);
double thedensity = 0;
foreach (string s in keywordsarray)
{
if (s != "")
{
keywordcount = KeywordCount(thearticle, s);
thedensity = keywordcount / wordcount;
thedensity = Math.Round(thedensity, 4) * 100;
if (thearticle.Contains(s))
{
isincluded = true;
}
else
{
isincluded = false;
}
lsikeywords.Add(new KeywordDensity()
{
included = isincluded,
keyword = s,
occurences = keywordcount.ToString(),
density = thedensity.ToString() + "%"
});
}
}
return lsikeywords;
}
private void txtArticle_TextChanged(object sender, EventArgs e)
{
if (haschanged == false)
haschanged = true;
lblWordCountNum.Text = WordCount(txtArticle.Text).ToString();
dataGrid.DataSource = LoadCollectionData();
}
private void dataGrid_MouseUp(object sender, MouseEventArgs e)
{
int cursorpos = 0;
string copied = "";
if (dataGrid.CurrentCellAddress.X == 1) //Only grab content if the "Keyword" column has been clicked on
copied = " " + dataGrid.CurrentCell.Value.ToString() + " ";
cursorpos = txtArticle.SelectionStart;
txtArticle.Text = txtArticle.Text.Insert(cursorpos, copied);
}
What's even more odd, is that when I click on any of the rows, then they immediately update. However, unless the row is clicked on (unless it's the top one) it doesn't update.
Because of this, I suspect there may be some property I need to set on the dataGrid itself, or I need to somehow tell each row to refresh through code.
What's the dealio?
EDIT: It appears that the only reason that the cell that's clicked on updates is because I actively grab content from the cell. I commented out the code below and it stopped updating even when clicked on. It then would only update the top row's values and that's it.
Code:
//Moved above in EDIT 3
EDIT 2: Here's the class declaration for KeywordDensity:
//Moved above in EDIT 3
EDIT 3: Posted whole schebang.
I modified the code slightly, try this code.
string[] keywordsarray = keywordslower.Split
(new char[] {'\r','\n' }, StringSplitOptions.RemoveEmptyEntries);
You may need to Invalidate() the control to trigger a repaint.
call the DataBind() method of the datagrid. That should do.
Update
There's a ResetBindings() in that case.