I have a listview with diffrent entries (see figure (A). I would like to extract some specific rows based on a condition. So far, i have this code:
private void Button2_Click(object sender, EventArgs e)
{
ArrayList listing = new ArrayList();
for (int i = 0; i < listView2.Items.Count; i++)
{
string columnOne = listView2.Items[i].Text;
string columnTwo = listView2.Items[i].SubItems[1].Text;
int numb = int.Parse(listView2.Items[i].SubItems[2].Text);
string columnThree = listView2.Items[i].SubItems[3].Text;
if(numb >= 2)
{
listing.Add($"{columnOne},{columnTwo},{numb},{columnThree}");
}
}
foreach (string item in listing)
{
listView2.Items.Clear();
ListViewItem listItem = new ListViewItem();
var separ = item.Split(',');
listItem.Text = separ[0].Trim();
listItem.SubItems.Add(separ[1]);
listItem.SubItems.Add(separ[2]);
listItem.SubItems.Add(separ[3]);
listView2.Items.Add(listItem);
}
}
I get figure (B), but normally i should get figure (C). How can this be achieved?
you shouldn't clear listview in foreach loop. do it once:
listView2.Items.Clear();
foreach (string item in listing)
{
// listView2.Items.Clear();
ListViewItem listItem = new ListViewItem();
var separ = item.Split(',');
listItem.Text = separ[0].Trim();
listItem.SubItems.Add(separ[1]);
listItem.SubItems.Add(separ[2]);
listItem.SubItems.Add(separ[3]);
listView2.Items.Add(listItem);
}
Removing the non matching items from the list makes more sense here. For your problem, execute a backward loop, try to convert the text of the third subitem to integer value using the int.TryParse method, and remove the ListViewItem if the value is less than 2.
private void button2_Click(object sender, EventArgs e)
{
for (var i = listView2.Items.Count - 1; i >= 0; i--)
{
if (int.TryParse(listView2.Items[i].SubItems[2].Text, out var num) && num < 2)
{
listView2.Items.RemoveAt(i);
}
}
}
Yet, if you want to get a list of matching items:
// +
using System.Collections.Generic;
private void button2_Click(object sender, EventArgs e)
{
var items = new List<ListViewItem>();
for (var i = 0; i < listView2.Items.Count; i++)
{
if (int.TryParse(listView2.Items[i].SubItems[2].Text, out var num) && num >= 2)
{
items.Add(listView2.Items[i]);
}
}
// ...
}
Or LINQ way:
// +
using System.Linq;
private void button2_Click(object sender, EventArgs e)
{
var items = listView2.Items.Cast<ListViewItem>()
.Where(x => int.TryParse(x.SubItems[2].Text, out var num) && num >= 2)
.ToList();
// ...
}
As a side note, using the ArrayList class is not recommended, use the List<T> class instead.
Related
Hello guys I am new to coding, and new to arrays as well and I was wondering how can I make this code to stop when there is no more names in the array, and from stop saying the number 10 always before the names. As well to show the position of the names one number above, not just starting from 0, but from 1.
Here is what I have so far.
string[] list = new string[10];
int pos = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string StudentName;
StudentName = textBox1.Text;
list[pos] = StudentName;
pos++;
textBox1.Text = "";
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show(list.GetLength(0).ToString());
string message;
for (int i = 0; i < lista.GetLength(0); i++)
{
message = "";
message = "The student" + " " + list[i] + " has the position " + i ;
MessageBox.Show(message);
}
}
Use a dynamic array, aka List<T>
List<string> list = new List<string>();
Instead of manually keeping track of the position, just add the item to the end:
list.Add(StudentName);
You can check the number of current items in the list by using .Count.
for (int i = 0; i < list.Count; i++) {...}
But you can also use a foreach loop to iterate over all the items in the list, but this way you do not get the position automatically.
foreach(var item in list){...}
For the sake of completeness, another way would be to filter out empty entries.
Linq is especially great for working with Enumerables like these:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where?view=net-6.0
using System;
using System.Linq;
public class Program
{
public static void Main()
{
string[] list = new string[10];
list[0] = "test1";
list[1] = "test2";
for (var index = 0; index < list.Length; index++)
{
var s = list[index];
Console.WriteLine($"[{index}] {s}");
}
// Filter out null, an empty string or only whitespace characters from the array
list = list
.Where(c => !string.IsNullOrWhiteSpace(c))
.ToArray();
Console.WriteLine("==========================");
for (var index = 0; index < list.Length; index++)
{
var s = list[index];
Console.WriteLine($"[{index}] {s}");
}
}
}
https://dotnetfiddle.net/g7e0Nm
First you can specify the maximum capacity of your array using a const
const int arrayCapacity = 10;
string[] list = new string[arrayCapacity];
int pos = 0;
Then you should add some validation if the array is full, according to your maximum capacity, and/or if the textbox is empty.
private void button1_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(textBox1.Text))
{
MessageBox.Show("Textbox was empty");
return;
}
if (pos > arrayCapacity - 1)
{
MessageBox.Show("Array is full");
textBox1.Clear();
return;
}
list[pos] = textBox1.Text;
pos++;
textBox1.Clear();
}
And the last step is to create a new array in any case you have a smaller number of students than your initial array's capacity
private void button2_Click(object sender, EventArgs e)
{
var arr = list.Where(x => !string.IsNullOrEmpty(x)).ToArray();
for (int i = 0; i < arr.Length; i++)
{
string message = "The student" + " " + arr[i] + " has the position " + (i + 1);
MessageBox.Show(message);
}
}
I have a ListBox which I populate like this:
var dtCustomers = db.GetTableBySQL(query).AsEnumerable().Select(rows =>
new CustomersModel
{
Name = rows.Field<string>("Name"),
ProjectKey = rows.Field<int>("ProjectKey")
});
lstCustomers.DataSource = dtCustomers.ToList();
lstCustomers.DisplayMember = "Name";
lstCustomers.ValueMember = "ProjectKey";
lstCustomers.ClearSelected();
Now I want to create TextBox with search button to look inside this list and search by item selected as:
private void btnSearch_Click(object sender, EventArgs e)
{
lstCustomers.SelectedItems.Clear();
for (int i = lstCustomers.Items.Count - 1; i >= 0; i--)
{
if (lstCustomers.Items[i].ToString().ToLower().Contains(txtSearch.Text.ToLower()))
{
lstCustomers.SetSelected(i, true);
}
}
lblitems.Text = lstCustomers.SelectedItems.Count.ToString() + "items found";
}
Problem is it never finds anything. I think it is because it is comparing by ValueMember instead of DisplayMember. Can I search in the list by DisplayMember?
You can use pattern matching for this since the underlying items will be your CustomersModel:
private void btnSearch_Click(object sender, EventArgs e)
{
lstCustomers.SelectedItems.Clear();
int matchCount = 0;
for (int i = lstCustomers.Items.Count - 1; i >= 0; i--)
{
if (lstCustomers.Items[i] is CustomersModel customer &&
customer.Name.IndexOf(txtSearch.Text, StringComparison.OrdinalIgnoreCase) > -1)
{
matchCount++;
lstCustomers.SetSelected(i, true);
}
}
lblItems.Text = $"{matchCount} item{(matchCount > 1 ? "s" : "")} found";
}
I'm currently working on a calculator but 2 of my algorithms are not working correctly.
In my history (listbox) I get the numbers from the calculator and I have a bottom that finds the smallest number. I get an error with my code.
I want to have a [sorting] bottom that sorts the numbers ascending or descending. I've tried things as listbox1.sorted but I only get it to work as alphabetic.
If you know what I'm doing wrong with nr.1 or know how to fix a sorting algorithm please let me know.
int count = 0;
int tal = 0;
double Mtal = 999999999999999999;
bool hit;
int count1 = 0;
private void button26_Click(object sender, EventArgs e)
{
while (count < 100)
{
foreach (var Listboxitem in listBox1.Items)
{
hit = false;
if (Convert.ToDouble(Listboxitem) < Mtal)
{
Mtal = Convert.ToDouble(Listboxitem);
hit = true;
}
count = count + 1;
if (hit)
{
count1 = count;
}
}
}
this.listBox1.SelectedIndex = count1 - 1;
}
Your values in ListBox are Integers. So change the declaration of your variable Mtal from double to int. And then, instead of Convert.ToDouble() use int.Parse(), because you need integers for comparing to existing min value.
Something like this should work for you:
int count = 0;
int tal = 0;
int Mtal = int.MaxValue;
bool hit;
int count1 = 0;
private void button26_Click(object sender, EventArgs e)
{
while (count < 100)
{
foreach (var Listboxitem in listBox1.Items)
{
hit = false;
if (int.Parse(Listboxitem.ToString()) < Mtal)
{
Mtal = int.Parse(Listboxitem.ToString());
hit = true;
}
count = count + 1;
if (hit)
{
count1 = count;
}
}
}
this.listBox1.SelectedIndex = count1 - 1;
}
And then for Ordering I would suggest you to use LINQ on List<ListItem>. For your example:
private void button_OrderByDescencing_Click(object sender, EventArgs e)
{
List<ListItem> items= new List<ListItem>();
foreach (ListItem a in lb.Items)
{
items.Add(a);
}
items=items.OrderByDescending(a => int.Parse(a.Value)).ToList();
foreach (ListItem a in items)
{
listBox1.Items.Add(a);
}
}
And for ascending:
private void button_OrderByAscending_Click(object sender, EventArgs e)
{
List<ListItem> items= new List<ListItem>();
foreach (ListItem a in lb.Items)
{
items.Add(a);
}
items= items.OrderBy(a => int.Parse(a.Value)).ToList();
foreach (ListItem a in items)
{
listBox1.Items.Add(a);
}
}
I am nearly to the answer but annoyingly, not quite.
So far my code is:
private void lstIndividuals_SelectedIndexChanged(object sender, EventArgs e)
{
var individual = lstIndividuals.SelectedItem as Individual;
var tempSimilarFilesToFile1 = new HashSet<Individual>();
int Counter = 0;
foreach (KeyValuePair<int, Individual> kvpInd in _Individuals1)
{
tempSimilarFilesToFile1 = new HashSet<Individual>();
foreach (KeyValuePair<int, Individual> kvpInd2 in _Individuals2)
{
if (kvpInd.Value.name.name.ToLower() == kvpInd2.Value.name.name.ToLower())
{
Counter++;
similarInds.Add(kvpInd.Value);
if (Counter >= 1)
{
tempSimilarFilesToFile1.Add(kvpInd2.Value);
}
}
}
lstIndividuals2.DataSource = tempSimilarFilesToFile1.ToList();
lstIndividuals2.DisplayMember = "DisplayName";
lstIndividuals2.ValueMember = "id";
}
As you can probably see, the lstIndividuals2 listbox items are zooming through really fast. I would just like to click on an item in lstIndividuals
Then I would like that to display similar records found (anything that abides by the rule kvpInd.value.name.name == kvpInd2.value.name.name)
All similar items, I would like to be stored in tempSimilarFilesToFile1 and that to be the datasource for the lstIndividual2
I apologise if I have explained badly.
Thank you.
You init the tempSimilarFilesToFile1 in the outer loop every time, so you actually get a list contains the items in _Individuals2 which are the same as the final item in _Individuals1. Just try to comment the init statement in the outer loop and see if that helps.
private void lstIndividuals_SelectedIndexChanged(object sender, EventArgs e)
{
var individual = lstIndividuals.SelectedItem as Individual;
var tempSimilarFilesToFile1 = new HashSet<Individual>();
int Counter = 0;
foreach (KeyValuePair<int, Individual> kvpInd in _Individuals1)
{
// comment the statement below
//tempSimilarFilesToFile1 = new HashSet<Individual>();
foreach (KeyValuePair<int, Individual> kvpInd2 in _Individuals2)
{
if (kvpInd.Value.name.name.ToLower() == kvpInd2.Value.name.name.ToLower())
{
Counter++;
similarInds.Add(kvpInd.Value);
if (Counter >= 1)
{
tempSimilarFilesToFile1.Add(kvpInd2.Value);
}
}
}
lstIndividuals2.DataSource = tempSimilarFilesToFile1.ToList();
lstIndividuals2.DisplayMember = "DisplayName";
lstIndividuals2.ValueMember = "id";
}
I have 3 check boxes in each row of 8 total rows. I want to have the third checkbox in each row to get checked only when the first two checkboxes are unchecked. I do not want to write a checkRow() method for each row.
What is the best way to go about it?
private void checkRow()
{
for (int i = 0; i < 8; i++)
{
var arraylist = new[] { checkbox1, checkbox2, checkbox3 };
if (checkbox1.Checked || checkbox2.Checked)
{
arraylist[2].Checked = false;
}
else
arraylist[2].Checked = true;
}
}
private void checbox1_CheckedChanged(object sender, EventArgs e)
{
checkRow();
}
private void checbox2_CheckedChanged(object sender, EventArgs e)
{
checkRow();
}
private void checbox3_CheckedChanged(object sender, EventArgs e)
{
checkRow();
}
In response.
private void checkRow()
{
var arraylist = new[] { checkEdit1, checkEdit2, checkEdit3 };
var arraylist1 = new[] { checkEdit4, checkEdit5, checkEdit6 };
var arraylist2 = new[] { checkEdit7, checkEdit8, checkEdit9 };
var array = new[] { arraylist, arraylist1, arraylist2 };
for (int i = 0; i < 8; i++)
{
//if checkedit1 or checkedit2 is checked the checkedit3 should not be checked
if (array[i]....Checked || array[i]....Checked)
{
arraylist[i]...Checked = false;
}
else
arraylist[i]...Checked = true;
}
}
I was trying to do something like this so that I dont have to write the checkRow() for each row
You should use the same method as the handler for all three delegates.
chkbox.CheckedChanged += new EventHandler(chkbox_CheckedChanged);
chkbox2.CheckedChanged += new EventHandler(chkbox_CheckedChanged);
chkbox3.CheckedChanged += new EventHandler(chkbox_CheckedChanged);
private void chkbox_CheckedChanged(object sender, EventArgs e)
{
// do your stuff here
}
Assuming you're not using a DataGridView or other way of organizing them into logical rows, why don't you do the following:
Store the checkboxes in an array so you have easy access to them.
CheckBox[,] checkArray = new CheckBox[8,3]...
Store the row index in the Tag property of the first and second checkboxes.
checkBox01.Tag = 0;
checkBox02.Tag = 0;
checkBox11.Tag = 1;
checkBox12.Tag = 1;
Have all the first and second checkboxes point to the same event handler:
checkBox01.CheckedChanged += new EventHandler(aCheckBox_CheckedChanged);
checkBox02.CheckedChanged += new EventHandler(aCheckBox_CheckedChanged);
checkBox11.CheckedChanged += new EventHandler(aCheckBox_CheckedChanged);
checkBox12.CheckedChanged += new EventHandler(aCheckBox_CheckedChanged);
In the event handler, you now know exactly which check box to update and no longer have to loop:
private void aCheckBox_CheckedChanged(object sender, EventArgs e)
{
int rowIndex = (int)((CheckBox)sender).Tag;
checkArray[rowIndex,2].Checked = !(checkArray[rowIndex,0].Checked ||
checkArray[rowIndex,1].Checked);
}
You can also do this using string lookups with the checkbox name, but it is surely slower and is a pain to refactor later if you choose to rename the checkboxes.