I have data which I import from textfiles, transfer to an sqlite db, then transfer that into LISTS. Now I want to show these lists to the user in a LISTVIEW. Each column should contain a list.
Below, the contents of the second column are perfectly fine. But, the 3rd and the fourth column should be vertically filled with the items that correspond to their color values.
I.e from the code below, I want to populate the 3rd and 4th column with the MaxLen list and PercentPopList list. (Yes I know that I skipped a column, but i'll fix that later)
I'm new to programming and I cant figure out how to make that work.
ListViewItem lvi = new ListViewItem();
foreach (object o in SeqIrregularities)
{
lvi.SubItems.Add(o.ToString());
listView1.Items.Add(lvi);//Adds a new row
lvi = new ListViewItem();
}
listView1.Items.Add(lvi);//Adds a new row
lvi = new ListViewItem();
foreach (object a in MaxLen)
{
lvi.SubItems.Add(a.ToString());
}
listView1.Items.Add(lvi);//Adds a new row
lvi = new ListViewItem();
foreach (object b in PercentPopList)
{
lvi.SubItems.Add(b.ToString());
}
listView1.Items.Add(lvi);//Adds a new row
Your data is in the wrong format. Simplifying, you seem to have data like this:
var firstColumnValues = new List<int>();
var secondColumnValues = new List<int>();
var thirdColumnValues = new List<int>();
While each individual list may make sense on its own, they currently don't relate to each other in any meaningful way. What you need to do is think about the format of the object which represents one "record" of data. Still overly-simplified, something like this:
class RecordOfValues
{
public int FirstValue { get; set; }
public int SecondValue { get; set; }
public int ThirdValue { get; set; }
}
Then you'd just have one list of them:
var listOfRecords = new List<RecordOfValues>();
At this point you would have a list of "records" to bind to the ListView.
As far as I understand that you don't have too much experience and cannot easily come up with an algorithm accounting for the suggested modifications; here you have a sample code showing how to extend your code to populate three different columns from 3 different lists:
List<string> SeqIrregularities = new List<string>();
SeqIrregularities.Add("1");
SeqIrregularities.Add("2");
SeqIrregularities.Add("3");
List<string> MaxLen = new List<string>();
MaxLen.Add("4");
MaxLen.Add("5");
MaxLen.Add("6");
List<string> PercentPopLis = new List<string>();
PercentPopLis.Add("7");
PercentPopLis.Add("8");
PercentPopLis.Add("9");
PercentPopLis.Add("10");
PercentPopLis.Add("11");
int totItems = SeqIrregularities.Count - 1;
if (MaxLen.Count - 1 > totItems) totItems = MaxLen.Count - 1;
if (PercentPopLis.Count - 1 > totItems) totItems = PercentPopLis.Count - 1;
for (int i = 0; i <= totItems; i++)
{
ListViewItem lvi = new ListViewItem();
string item1 = "";
string item2 = "";
string item3 = "";
if (SeqIrregularities.Count - 1 >= i) item1 = SeqIrregularities[i];
if (MaxLen.Count - 1 >= i) item2 = MaxLen[i];
if (PercentPopLis.Count - 1 >= i) item3 = PercentPopLis[i];
lvi.SubItems.Add(item1);
lvi.SubItems.Add(item2);
lvi.SubItems.Add(item3);
listView1.Items.Add(lvi);
}
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 ListView that is dynamic and Columns name need to change dynamic so i create this:
var gridView = new GridView();
this.lvWorkers.View = gridView;
foreach(string c in columnName)
{
gridView.Columns.Add(new GridViewColumn
{
Header = c.Remove(0, 5),
DisplayMemberBinding = new Binding(c)
});
}
Now i want add Items to this list but there is no SubItems like in Win Forms. I find similar problems, the answer was to make class that is defined. Add Items to Columns in a WPF ListView
I need to add Items dynamic.
Win Forms which is not work.
foreach (OneStudentEvent e in oneEventList)
{
ListViewItem item = new ListViewItem(e.Indeks.ToString());
item.SubItems.Add(e.eventString);
...
lvWorkers.Items.Add(item);
}
EDIT
Now i remove DisplayMemberBinding = new Binding(c)
and add:
lvWorkers.ItemsSource = getList();
private ArrayList getList()
{
ArrayList data = new ArrayList();
for(int i=0; i<20; i++)
{
List<string> tempList = new List<string>();
for(int j = 0; j < 30; j++)
{
tempList.Add(j.ToString());
}
data.Add(tempList);
}
return data;
}
And i don't see string in list but word: (Collection). I know that this is my bad to show collection no single string, but i don't know hot to make it.
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
Using c#, winforms.
Background:
The user should be able to select items from my menu strip, and then based on that the list view columns should be populated. Example: Select percent from 100-80 % then columns 1 and 2 get populated. Select total trans from <1000 and then column 3 and 4 get populated.
Problem:
When adding items to my listview, say I select option 1 from menu strip. Then columns 1 and 2 get filled up. Good. BUT right after if I select option from total trans, the column 3 and 4 do get filled up, BUT there is a ton of WHITEspace in the columns. Basically, the columns should not have white space when getting filled up.
This is what I mean: Notice the whitespace (outlined by red). First I selected option 1, then as soon as I selecte the option to populate column 3 and 4, they filled, but with whitespace. The column values for col 3 and 4 should have nothing above them in white.
Also here: I select another option from menu strip (for col 1 and 2) , after selecting the option to fill column 3 and 4, and more whitespace:
Code:
// Fill Column 1 and 2 from option 1
private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
int totItems = Seq3.Count - 1;
if (PercentPopTolerance1.Count - 1 > totItems) totItems = PercentPopTolerance1.Count - 1;
for (int i = 0; i <= totItems; i++)
{
ListViewItem lvi = new ListViewItem();
string item1 = "";
string item2 = "";
if (Seq3.Count - 1 >= i) item1 = Seq3[i].ToString();
if (PercentPopTolerance1.Count - 1 >= i) item2 = PercentPopTolerance1[i].ToString();
lvi.SubItems.Add(item1);
lvi.SubItems.Add(item2);
listView2.Items.Add(lvi);
}
}
// Percent tolerance from 80-60%
// Fill Column 1 and 2 from option 2
private void toolStripMenuItem3_Click_1(object sender, EventArgs e)
{
ClearColumn("columnHeader5");
int totItems = Seq4.Count - 1;
if (PercentPopTolerance2.Count - 1 > totItems) totItems = PercentPopTolerance2.Count - 1;
for (int i = 0; i <= totItems; i++)
{
ListViewItem lvi = new ListViewItem();
string item1 = "";
string item2 = "";
if (Seq4.Count - 1 >= i) item1 = Seq4[i].ToString();
if (PercentPopTolerance2.Count - 1 >= i) item2 = PercentPopTolerance2[i].ToString();
lvi.SubItems.Add(item1);
lvi.SubItems.Add(item2);
listView2.Items.Add(lvi);
}
}
// Fill columns 3 and 4 from option in total trans menustrip
// Total trans tolerance < 1000
private void etcToolStripMenuItem_Click(object sender, EventArgs e)
{
int totItems = YYMMt21.Count - 1;
if (TotalTransIrregularitiest21.Count - 1 > totItems) totItems = TotalTransIrregularitiest21.Count - 1;
for (int i = 0; i <= totItems; i++)
{
ListViewItem lvi = new ListViewItem();
string item1 = "";
string item2 = "";
if (YYMMt21.Count - 1 >= i) item1 = YYMMt21[i].ToString();
if (TotalTransIrregularitiest21.Count - 1 >= i) item2 = TotalTransIrregularitiest21[i].ToString();
// Skip first 2 columns
lvi.SubItems.Add(string.Empty);
lvi.SubItems.Add(string.Empty);
lvi.SubItems.Add(item1);
lvi.SubItems.Add(item2);
listView2.Items.Add(lvi);
}
}
EDIT: Trying User suggestion:
New problem arises: what is supposed to be in column 3 and 4 vertically now fills the listview from the first row horizontally:
My attempt:
private void etcToolStripMenuItem_Click(object sender, EventArgs e)
{
int totItems = YYMMt21.Count - 1;
if (TotalTransIrregularitiest21.Count - 1 > totItems) totItems = TotalTransIrregularitiest21.Count - 1;
for (int i = 0; i <= totItems; i++)
{
ListViewItem lvi = new ListViewItem();
string item1 = "";
string item2 = "";
if (YYMMt21.Count - 1 >= i) item1 = YYMMt21[i].ToString();
if (TotalTransIrregularitiest21.Count - 1 >= i) item2 = TotalTransIrregularitiest21[i].ToString();
// Skip first 2 columns
lvi.SubItems.Add(string.Empty);
lvi.SubItems.Add(string.Empty);
int rowToPopulate = 0;
int colToPopulate = 0;
if (rowToPopulate <= listView2.Items.Count - 1)
{
//Editing an existing row/ListViewItem
listView2.Items[rowToPopulate].SubItems.Insert(colToPopulate, new ListViewItem.ListViewSubItem() { Text = item1 });
// How would I also add item2?
// listView2.Items[rowToPopulate].SubItems.Insert(colToPopulate, new ListViewItem.ListViewSubItem() { Text = item2 });
}
else
{
//Adding a new row/ListViewItem
// ListViewItem lvi = new ListViewItem();
lvi.SubItems.Add(item1);
lvi.SubItems.Add(item2);
//Add all the other Subitems as usual
listView2.Items.Add(lvi);
}
//listView2.Items.Add(lvi);
}
}
You can alternate Items.Add and Items.SubItems.Insert. Sample code:
string curItem = "curVal";
int rowToPopulate = 0;
int colToPopulate = 0;
if (rowToPopulate <= listView2.Items.Count - 1)
{
//Editing an existing row/ListViewItem
listView2.Items[rowToPopulate].SubItems.Insert(colToPopulate, new ListViewItem.ListViewSubItem() { Text = curItem });
}
else
{
//Adding a new row/ListViewItem
ListViewItem lvi = new ListViewItem();
lvi.SubItems.Add(curItem);
//Add all the other Subitems as usual
listView2.Items.Add(lvi);
}
This code checks whether the row being analysed (rowToPopulate) has already been populated or not. If it hasn't been populated yet, you can use the code so far (under the else statement, including as many SubItems as columns by letting blank the ones for which no information is available). If this is the second time that you analyse this row (some columns have already been populated and some other ones were left blank), you take the given ListViewItem/row (listView2.Items[rowToPopulate]) and insert the new element in the SubItem/column you wish.
From what I can tell on your code, you just keep adding more items on the events, supplying String.Empty for the columns you're trying to skip. If you want the new values from the next event to appear on the same row as values already present, you'll have to update the already existing rows SubItems and supply which values are to go on which row.
Edit: I accomplished what you're trying to do with the below sample. This assumes that you know or can get the size of each list you're trying to add to each column. You'll have to implement some null checking etc to make sure you're not referencing null cells in the lists. Just expand on this sample and tailor it to your exact situation.
List<string> sList = new List<string>() { "1", "2", "3", "4", "5" };
List<string> lList = new List<string>() { "1", "2", "3", "4", "5", "6", "7", "8" };
private void button1_Click(object sender, EventArgs e)
{
listView1.Clear();
addColumns();
for (int i = 0; i < sList.Count(); i++)
{
var item1 = new ListViewItem(sList[i]);
item1.SubItems.Add(String.Empty);
listView1.Items.Add(item1);
}
}
private void button2_Click(object sender, EventArgs e)
{
listView1.Clear();
addColumns();
for (int i = 0; i < lList.Count(); i++)
{
if (i < sList.Count())
{
var item2 = new ListViewItem(sList[i]);
item2.SubItems.Add(lList[i]);
listView1.Items.Add(item2);
}
else
{
var item3 = new ListViewItem(String.Empty);
item3.SubItems.Add(lList[i]);
listView1.Items.Add(item3);
}
}
}
private void addColumns()
{
listView1.Columns.Add("Column 1", -2, HorizontalAlignment.Left);
listView1.Columns.Add("Column 2", -2, HorizontalAlignment.Left);
}
I have been researching for almost two weeks now and found nothing helpful.
I have a listview with a few columns, the last column is a price column, I need to have another column that calculates the price column and a textbox, for each row in the listview. Any help will be highly appreciated.
Sorry, I am new to programming and at the moment I can only sum the column, This is all I got.
List<string> last = new List<string>();
last.AddRange(new string[] { "one", "two", "three", "four" });
int column = 1 ; int.Parse(TextBox1.text)
int row = 0;
foreach (var value in last)
{
if (!(column >= listView1.Columns.Count))
{
ListViewItem item = new ListViewItem();
listView1.Items.Add(item);
ListViewItem.ListViewSubItem lvsi = new ListViewItem.ListViewSubItem();
lvsi.Text = value.ToString();
listView1.Items[row].SubItems.Insert(column, lvsi);
row++;
}
}
I think should be something like this (where n is the number of the column with the price calculated, and i the column with the initial price):
int currency = int.Parse(Textbox1.Text);
int markup = int.Parse(Textbox2.Text);
int shippingcost = int.Parse(Textbox3.Text).
foreach(ListViewItem item in listView.Items)
{
item.SubItems[n].value = ( ((int)item.SubItems[i].value * currency) + markup + shippingcost ).ToString();
}
With this, foreach ListViewItem you cast to int the value of the column with the price, calculate the final price with the value of a textbox, and convert it into a string and put the final value the desired column.