I have 2 listboxes in my Windows C# WinForms application. I have written the code to move items between my 2 listboxes. I can select any/multiple items and move them between the boxes. However if I select the bottom item in the listbox and move it to the other listbox, then the content in the table it was moved from shows up incorrectly. Instead of showing the actual contents, it's showing:- ProgramName__.objectname for each entry that was above the entry i moved! This only happens with the last item in the listbox. If i select the entry that shows up wrong and move it to the other listbox, the correct information shows up.
This appears to me to be a bug, but I'm not sure. I can move any other item in the listbox and both listboxes show up properly.
public class customers
{
public int id { get; set; }
public string name {get; set; }
}
this.table1Box.DataSource = this.customersBindingSource;
this.table1Box.DisplayMember = "name";
this.table1Box.Name = "Table1Name";
this.table1Box.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
this.table1Box.Sorted = true;
this.table1Box.TabIndex = 13;
this.table1Box.ValueMember = "id";
this.table2Box.DataSource = this.customersBindingSource;
this.table2Box.DisplayMember = "name";
this.table2Box.Name = "Table2Name";
this.table2Box.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
this.table2Box.Sorted = true;
this.table2Box.TabIndex = 14;
this.table2Box.ValueMember = "id";
// Click method for moving table 1 -> table 2
private void table1ToTable2Button_Click(object sender, EventArgs e)
{
foreach (int i in this.table1Box.SelectedIndices)
{
selectedCustomer = (customers)this.table1Box.Items[i];
table2List.Add(selectedCustomer);
table1List.Remove(selectedCustomer);
}
this.table1Box.DataSource = this.emptyList;
this.table1Box.DataSource = this.table1List;
this.table1Box.Update();
this.table2Box.DataSource = this.emptyList;
this.table2Box.DataSource = this.table2List;
this.table2Box.Update();
}
![Picture at Start of program] http://www.mclenaghan.com/Pic1.jpg
![Picture after moving last item] http://www.mclenaghan.com/Pic2.jpg
![Picture moving item 2] http://www.mclenaghan.com/Pic3.jpg
Make sure you are binding to BindingList<customers>.
You don't need to set the DataSource to an empty list and then set to the actual list again and then call ListBox.Update(). This seems to be working but it also means you are doing wrong in your binding.
One more thing- Do not edit the designer-generated code by hand, use the Properties Pane. I find even if I change the code sequence in the InitializeComponent method, the listbox can display incorrectly.
BindingList<customers> table1List;
BindingList<customers> table2List;
public FormWith2Listboxes()
{
InitializeComponent();
table1List = new BindingList<customers>();
table1List.Add(new customers() { id = 1, name = "name1" });
table1List.Add(new customers() { id = 2, name = "name2" });
table1List.Add(new customers() { id = 3, name = "name3" });
table2List = new BindingList<customers>();
table2List.Add(new customers() { id = 4, name = "name4" });
this.table1Box.DataSource = this.table1List;
this.table2Box.DataSource = this.table2List;
}
private void table1ToTable2Button_Click(object sender, EventArgs e)
{
foreach (int i in this.table1Box.SelectedIndices)
{
var selectedCustomer = (customers)this.table1Box.Items[i];
table2List.Add(selectedCustomer);
table1List.Remove(selectedCustomer);
}
}
Related
assume I have 2 columns in gridview : column A and column B. I want to delete the whole row if Column B has no value. this code checks column B if it doesn't have any value. next, how to enter the delete command based on the value obtained from the code ?
private void Button1_Click(object sender, EventArgs e)
{
foreach (GridViewRowInfo row in DGV1.Rows)
{
if (row.Cells[1].Value == null || Convert.ToString(row.Cells[1].Value) == string.Empty)
{
MessageBox.Show("Null value");
}
}
}
Hopefully I can offer a couple of tips for working with RadGridView or really most any grid view. First, use BeginInvoke to avoid blocking the Click message which allows the UI thread to return from the click handler (mouse returns to the up position, any new button state is painted).
private void buttonRemove_Click(object sender, EventArgs e)
{
// Do not block the click event.
BeginInvoke((MethodInvoker)delegate
{
onButtonRemove();
});
}
Next make an array of records (or rows) that need to be removed. If your view is bound to a DataSource this is especially easy using System.Linq. Then simply remove from DataSource.
void onButtonRemove()
{
// Perform Linq query to see what needs to be removed
var removes =
DataSource
.Where(record => string.IsNullOrWhiteSpace(record.ColumnB));
// Cast to an array before iterating to
// avoid "CollectionWasModified" exception.
foreach (var record in removes.ToArray())
{
DataSource.Remove(record);
}
}
This particular code defines a row with this Record class:
class Record
{
public string ColumnA { get; set; } = "SomeValue";
public string ColumnB { get; set; }
}
If you were using a Winforms DataGridView it could initialize like this:
BindingList<Record> DataSource = new BindingList<Record>();
private void InitializeDataGridView()
{
dataGridView1.AllowUserToAddRows = false;
dataGridView1.DataSource = DataSource;
// Add one or more records to auto-create columns.
DataSource.Add(new Record { ColumnB = "Not empty or null"});
DataSource.Add(new Record { ColumnB = String.Empty});
DataSource.Add(new Record { ColumnB = null});
// Column formatting
dataGridView1.Columns[nameof(Record.ColumnA)].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridView1.Columns[nameof(Record.ColumnB)].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
Your post is for Telerik.WinControls.UI.RadGridView but the initialization is very similar:
BindingList<Record> DataSource = new BindingList<Record>();
private void InitializeDataGridView()
{
DGV1.DataSource = DataSource;
// Add one or more records to auto-create columns.
DataSource.Add(new Record { ColumnB = "Not empty or null"});
DataSource.Add(new Record { ColumnB = String.Empty});
DataSource.Add(new Record { ColumnB = null});
// Column formatting
DGV1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
}
Hope this helps get you where you want to be.
I want to use the virtual mode of a DataGridView since I have more than 150k rows (always 2 columns). The data in the DataGridView is extracted from a file and is read-only(users can't add or remove rows). However, some of my rows needs to have a greater height than the others since the data displayed in it is on multiple lines.
I am currently filling my DataGridView like this:
private struct ContactEntry
{
public string Name { get; set; }
public string Addr { get; set; }
};
private void UpdateDataGridView(List<Contact> listContact)
{
List<ContactEntry> newList = new List<ContactEntry>();
for (int index = 0; index < listContact.Count; index++)
{
Contact ct = listContact[index];
string addresses = string.Empty;
if (Contact.Addrs != null)
{
// Construct list of addresses
foreach (string addr in Contact.Addrs)
{
addresses = String.Format("{0}{1}{2}", addresses, Environment.NewLine, addr);
}
// Removes first environment new line
addresses = addresses.Remove(0, 2);
var entry = new ContactEntry();
entry.Name = Contact.Name;
entry.Addr = addresses;
newList.Add(entry);
}
}
_dgvContacts = newList;
_dgvContacts.CellValueNeeded += _dgvContacts_CellValueNeeded;
// Set the row count
_dgvContacts.RowCount = newList.Count;
_dgvContacts.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
_dgvContacts.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;
if (_dgvContacts.CurrentCell != null)
{
_dgvContacts.CurrentCell.Selected = false;
}
}
private void _dgvContacts_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
switch (_dgvContacts.Columns[e.ColumnIndex].Name)
{
case "Name":
e.Value = _dgvContacts[e.RowIndex].Name;
break;
case "Addresses":
e.Value = _dgvContacts[e.RowIndex].Addr;
break;
}
}
With this, the UI loads quickly because of the virtual mode, but when the form loads, only the height of the first visible rows are adjusted. When I scroll down, the data in the rows are changed for new values from the list, but the height are not changing. However, when I resize the form, the rows height are updated like it should.
I am trying to generate a telerik report table dynamically. Actually, after lots of efforts besides surfing the web I have come to the following code which works fine but not presenting the desired output. Here is the code:
private void table1_ItemDataBinding(object sender, EventArgs e)
{
// Get data and bind it to the table
var processingTable = (sender as Telerik.Reporting.Processing.Table);
var data = GenerateTable(DomainClass.GetCurrentAsset());
if (processingTable != null) processingTable.DataSource = data;
// Better clear table before binding
table1.ColumnGroups.Clear();
table1.Body.Columns.Clear();
table1.Body.Rows.Clear();
HtmlTextBox txtGroup;
HtmlTextBox txtTable;
//int rowIndex = 0;
for (int i = 0; i <= data.Columns.Count - 1; i++)
{
var tableGroupColumn = new TableGroup();
table1.ColumnGroups.Add(item: tableGroupColumn);
txtGroup = new HtmlTextBox
{
Size = new SizeU(Unit.Inch(2.1), Unit.Inch(0.3)),
Value = data.Columns[i].ColumnName,
Style =
{
BorderStyle = { Default = BorderType.Solid },
BorderColor = { Default = Color.Black }
},
};
tableGroupColumn.ReportItem = txtGroup;
txtTable = new HtmlTextBox()
{
Size = new SizeU(Unit.Inch(2.2), Unit.Inch(0.3)),
Value = "=Fields." + data.Columns[i].ColumnName,
//Value = data.Rows[rowIndex][i].ToString(),
Style =
{
BorderStyle = { Default = BorderType.Solid },
BorderColor = { Default = Color.Black }
}
};
table1.Body.SetCellContent(0, columnIndex: i, item: txtTable);
//rowIndex++;
table1.Items.AddRange(items: new ReportItemBase[] { txtTable, txtGroup });
}
}
Here is a picture of DataTable which contains the table data:
Finally, the current out put which is of course not what needed:
So the problem is; The Account_Price column does not display the Prices, though retrieved from the data store and can be seen in the data table picture above.
I have traced line by line of the code and could find out the prices as tracing the code. But I have no idea why they are not shown in the browser.
Hope any one could help me,
Thank you very much
Apparently, this is a newer issue with the later Telerik reporting.
I found the answer in the Telerik forums here:
http://www.telerik.com/community/forums/reporting/telerik-reporting/incorrect-dynamic-table-columns.aspx
Basically, you need to assign a unique name the TableGroup column:
TableGroup tableGroupColumn = new TableGroup();
//add this :
tableGroupColumn.Name = i.ToString();
I'm trying to retrieve the selected item from a combobox, though i can't get it to work.
Form1 form = new Form1();
string cpuCount = form.comboBox1.SelectedItem.ToString();
Now, this is not returning anything. BUT, if i insert this code in my InitializeComponent(), it selects item with index = 3, and return that proper item.
comboBox1.SelectedIndex = 3;
Why does it behave like this? If I now select for example item with index = 5, it still will think the selected item is the one with index = 3.
---------- I think i should expand to show you how my code looks.
Form1 - adding all items to the comboboxes.
public partial class Form1 : Form
{
Profile profile = new Profile();
public Form1()
{
InitializeComponent();
Profile profile = new Profile();
string[] prof = profile.getProfiles();
foreach (var item in prof)
{
comboBox5.Items.Add(Path.GetFileNameWithoutExtension(item));
}
int ram = 1024;
for (int i = 0; i < 7; i++)
{
comboBox4.Items.Add(ram + " GB");
ram = ram * 2;
}
int vram = 512;
string size;
for (int i = 0; i < 5; i++)
{
if(vram > 1000)
{
size = " GB";
}
else
{
size = " MB";
}
comboBox2.Items.Add(vram + size);
vram = vram * 2;
}
for (int i = 1; i < 5; i++)
{
comboBox1.Items.Add(i * 2);
}
for (int i = 0; i < 5; i++)
{
comboBox3.Items.Add(i * 2);
}
private void button3_Click(object sender, EventArgs e)
{
string current = profile.currentProfile();
profile.saveProfile(current);
}
}
So, button3 is my "save"button.
And here is my "Profile"-class
class Profile
{
public string folder { get; set; }
public Profile()
{
this.folder = "Profiles";
if (!File.Exists(folder))
{
Directory.CreateDirectory(folder);
File.Create(folder + "/default.cfg").Close();
}
}
public string[] getProfiles()
{
string[] files = Directory.GetFiles(folder);
return files;
}
public void saveProfile(string filename)
{
Form1 form = new Form1();
string cpuCount = "cpuCount=" + form.comboBox1.SelectedItem;
string RAM = "maxRAM=" + form.comboBox4.SelectedItem;
string VRAM = "maxVRAM=" + form.comboBox2.SelectedItem;
string threads = "cpuThreads=" + form.comboBox3.SelectedItem;
string path = folder + "/" + filename;
StreamWriter sw = new StreamWriter(path);
string[] lines = { cpuCount, RAM, VRAM, threads };
foreach (var item in lines)
{
sw.WriteLine(item);
}
sw.Close();
}
public string currentProfile()
{
Form1 form = new Form1();
string selected = form.comboBox5.SelectedValue + ".cfg".ToString();
return selected;
}
}
Thank you.
The problem is that there is nothing selected in your ComboBox. You create your form and then, without previous user interaction, you want to get the SelectedItem which is null at that moment.
When you create ComboBox control and fill it with items, SelectedItem property is null until you either programratically set it (by using for example comboBox1.SelectedIndex = 3) or by user interaction with the control. In this case you are not doing anything of the above and that is why you are geting the mentioned error.
EDIT Based on the edited question
Change your code like this:
first change the saveProfile method so you could pass the four strings which you write into the text file. Note that you could alternatively pass the reference of the form but I wouldn't suggest you that. So change the method like this:
public void saveProfile(string filename, string cpuCount, string RAM , string VRAM , string threads)
{
string path = folder + "/" + filename;
using(StreamWriter sw = new StreamWriter(path))
{
sw.WriteLine("cpuCount=" + cpuCount);
sw.WriteLine("maxRAM=" + RAM );
sw.WriteLine("maxVRAM=" + VRAM );
sw.WriteLine("cpuThreads=" + threads);
}
}
And then call it from button3 Click event handler like this:
private void button3_Click(object sender, EventArgs e)
{
string current = profile.currentProfile();
string cpuCount = this.comboBox1.SelectedItem.ToString();
string RAM = this.comboBox4.SelectedItem.ToString();
string VRAM = this.comboBox2.SelectedItem.ToString();
string threads = this.comboBox3.SelectedItem().ToString();
profile.saveProfile(current, cpuCount, RAM, VRAM, threads);
}
Or alternatively
private void button3_Click(object sender, EventArgs e)
{
string current = profile.currentProfile();
profile.saveProfile(current, this.comboBox1.SelectedItem.ToString(), this.comboBox4.SelectedItem.ToString(), this.comboBox2.SelectedItem.ToString(), this.comboBox3.SelectedItem().ToString());
}
From what I can see, you are calling form.comboBox1.SelectedItem.ToString() right after the creation of Form1. This means that the cpuCount variable is initialized right after the form is created, thus far before you have the chance to change the selected item with your mouse.
If you want to retrieve the value of the combobox after it is changed, you can use the SelectedIndexChanged event.
First of all, add a Form_Load Event and put your code in the handler. (use constructor for property initialization and other variable initialization)
private void Form1_Load(object sender, EventArgs e)
{
this.comboBox1.SelectedItem= 5; // This will set the combo box to index 5
string cpuCount = this.comboBox1.SelectedText; // This will get the text of the selected item
}
so you get the value of item at index 5 in cpuCount variable.
The selected clause gives you the values AFTER you have selected something, by default(when you run your app) there is nothing selected in the comoboBox, hence, it displays the value as null, after selecting the item you can use the combobox's selectedItem, selectedIndex, selectedText and selectedValue properties.
You can also use databinding to display items in the combobox, which in my view is a better way then adding the items manually.
to databind your combobox you can use,
// Bind your combobox to a datasource, datasource can be a from a database table, List, Dataset, etc..
IDictionary<int, string> comboDictionary = new Dictionary<int, string>();
comboDictionary.Add(1, "first");
comboDictionary.Add(2, "second");
comboDictionary.Add(3, "third");
comboBox1.DataSource = comboDictionary;
comboBox1.DisplayMember = "Key";
comboBox1.ValueMember = "Value";
//
And here now you can use combobox1.SelectedIndex to go through the item collection in the datasource :) and it will give you the value against your keys when you use combobox1.SelectedValue. Hope this helps.
Your ComoboBox doesn't have items in it. So it will not return properly. You are accessing combobox selected value rights after making form object.
And if it comboBox has items then nothing is being selected. By default nothing is selected in comboBox. You need to set it. Use this. What it returns? Set comboBox.SelectedIndex and then get selectedItem.
int selectedIndex = form.comboBox1.SelectedIndex;
Try this. Add some items in ComboBox and then get selectedItem.
Form1 form = new Form1();
form.comboBox1.Add("Item 1");
form.comboBox1.Add("Item 2");
form.comboBox1.Add("Item 3");
form.comboBox1.SelectedIndex = 1;
string cpuCount = form.comboBox1.SelectedItem.ToString();
I have a DataGridView that is populated at runtime with a couple of ComboBoxColumn columns. For example,
var newCountryColumn = new DataGridViewComboBoxColumn();
newCountryColumn.HeaderText = "Country";
newCountryColumn.DataSource = CountryListArray.ToArray();
newCountryColumn.DisplayMember = "Name";
newCountryColumn.ValueMember = "Code";
And so on. Now, at runtime the user selects a file to open up, and it is parsed, line by line, into an array.
var lines = File.ReadAllLines(path + "\\" + choosenFile);
foreach (string line in lines) {
numOfRecords++;
errorCounter = 0;
string[] items = line.Split('\t').ToArray();
int billState = headerIndex[0] - 1;
int billCountry = headerIndex[1] - 1;
int shipState = headerIndex[2] - 1;
int shipCountry = headerIndex[3] - 1;
for (int i = 0; i < headerIndex.Count; i++) {
int index = headerIndex[i];
/*Get the state and country codes from the files using the correct indices*/
Globals.Code = items[index - 1].ToUpper();
//If the code can't be found in either list
if (!CountryList.ContainsKey(Globals.Code) && !StateList.ContainsKey(Globals.Code)) {
errorCounter++;
if (errorCounter == 1){
dataGridView1.Rows.Add(items);
}
}
}
}
Now, that works great, except for when I scroll over in the DataGridView, over to where the comboboxes are. Apparently the code doesn't like having a value from the items array being added to a pre-existing comboboxcolumn. And I get an error dialog:
The following exception occurred in the DataGridView: System.ArguementException: DataGridViewComboBoxCell value is not valid.
Can the item from the items array be shown in the combo box column?
newCountryColumn.DisplayMember = "Name";
newCountryColumn.ValueMember = "Code";
Tells newCountryColumn.DataSource to expect a collection with properties named Name and Code. But you pass it a string[]. That is wrong, which is what the error message is telling you.
There are several ways of doing this right, the most straightforward is to declare your own class with properties Name and Code:
class CountryTuple
{
public string Code { get; private set; }
public string Name { get; private set; }
public CountryTuple(string code, string name)
{
this.Code = code;
this.Name = name;
}
}
Now you can instantiate your collection:
var cts = new List<CountryTuple>();
Add instances to your collection::
cts.Add(new CountryTuple(items[index - 1].ToUpper(), whatever));
And assign it to your DataSource:
newCountryColumn.DataSource = cts;