C# Windows Forms how to get the ListView Items - c#

I am trying to create a string with items from a ListView in C#(Windows Forms). I have two columns and over hundreds of three digit numbers in my ListView. The values indicate which X and Y axis my mouse was on. But as soon as I try to output the values in e.g. a text box, only the last X and Y values appear, the rest are ignored.
What I have tried:
listView1.Items[a].SubItems[0].Text
int.Parse(listView1.Items[a].SubItems[0].Text)
maybe someone has a suggestion

You need to iterate over the items and subitems in this manner:
foreach (ListViewItem item in listView1.Items)
{
Debug.WriteLine($"Item: {item.Text}");
foreach (ListViewItem.ListViewSubItem subitem in item.SubItems)
{
Debug.WriteLine($"\tSubitem:{subitem.Text}");
}
}

Do you use a loop for your items? It's not clear where a comes from. You might also want to use a loop for your subitems.
you can loop through all items and subitems like this:
for (int i = 0; i < listView1.Items.Count; i++)
{
for (int k = 0; k < listView1.Items[i].SubItems.Count; k++)
{
string s = listView1.Items[i].SubItems[k].Text;
}
}

thanks for your help guys,
the only thing missing was the loop and this line Value += Environment.NewLine +
your suggestions both worked
foreach (ListViewItem item in listView1.Items)
{
Value += Environment.NewLine + item.Text;
foreach (ListViewItem.ListViewSubItem subitem in item.SubItems)
{
Value += Environment.NewLine + subitem.Text;
}
}
and
for (int i = 0; i < listView1.Items.Count; i++)
{
for (int k = 0; k < listView1.Items[i].SubItems.Count; k++)
{
Value += Environment.NewLine + listView1.Items[i].SubItems[k].Text;
}
}

Related

Losing value if backwards List printing matrix

I need to display a Sheet so that the lines are aligned bottom and left. If there are no 10 characters in the word, the number of "+" characters is added so that the total of the line is 10 characters (see my output).
Why, when I print a List, I lose one row?
What's wrong with my piece of code? This matrix should be 10X10.
My output
List<string> filtredList = new List<string>() { "Jacuzzi", "Action", "Chinchilla", "Squeezebox", "Academic", "Abstract" };
int row = 10;
filtredList = Sorting(filtredList); //method is sorting by descending.
foreach (var item in filtredList) Console.WriteLine("Item: " + item + " length: " + item.Length);
Console.WriteLine("-------------------------------------");
//AFTER SORTING IN LIST:
//1)Squeezebox 2)Chinchilla 3)Academic 4)Abstract 5)Jacuzzi 6)Action
for (int i = 10; i > 0; i--)
{
try
{
if (filtredList[i].Length != 10)
{
Console.Write(filtredList[i]);
row = 10 - filtredList[i].Length;
Console.WriteLine(string.Concat(Enumerable.Repeat("+", row)));
}
else Console.WriteLine(filtredList[i]);
}
catch (SystemException)
{
row = 10;
Console.WriteLine(string.Concat(Enumerable.Repeat("+", row)));
}
}
Because your for loop is never gets to 0:
for (int i = 10; i > 0; i--)
i goes from 10 to 1 and that's why the first item of your list never prints.
Note:
Index of first item of an array or a list is 0
The better code would be:
for (int i = 9; i >= 0; i--)
Although you can use better alternatives for some of your code, but this will solve your problem.
EDIT:
You can use this approach (just change the for part to this) to not raise any exceptions (because its not normally a use case for try-catch)and also get faster results:
for (int i = 9; i >= 0; i--)
{
if (i < filtredList.Count)
{
if (filtredList[i].Length != 10)
{
Console.Write(filtredList[i]);
row = 10 - filtredList[i].Length;
Console.WriteLine(new string('+', row));
}
else Console.WriteLine(filtredList[i]);
}
else
{
row = 10;
Console.WriteLine(new string('+', row));
}
}

C#: how to detect repeating values in an array and process them in such a way that each repeating value is only processed once?

I wrote this simple program:
class Program
{
static void Main(string[] args)
{
Console.Write("Number of elements in the array: ");
int numberOfElements = int.Parse(Console.ReadLine());
int[] array = new int[numberOfElements];
for(int i = 0; i < numberOfElements; i++)
{
Console.Write($"Element no {i+1}: ");
array[i] = int.Parse(Console.ReadLine());
}
for(int i = 0; i < array.Length; i++)
{
int count = 0;
for(int j = 0; j < array.Length; j++)
{
if(array[i] == array[j])
{
count++;
}
}
Console.WriteLine($"{array[i]} appears " + count + " times");
}
}
}
}
Is there any option to make the displayed values print only once?
For example, if there are three occurrences - the message displays three times. Is it possible to make it display once when there are more occurrences though?
You could use a GroupBy instead of the for loop
Groups the elements of a sequence.
var results = array
.GroupBy(x => x)
.Select(x => new {Value = x, Count = x.Count()});
foreach(var g in results)
Console.WriteLine($"{g.Value} appears {g.Count} times");
Or another way it to use a HashSet to keep track of what you have displayed. A HashSet is basically a collection that contains no duplicate elements. The Add methods returns true if it can add an element or false otherwise
HashSet<T>.Add(T) Method
returns true if the element is added to the HashSet object; false if the
element is already present.
var hashSet = new HashSet<int>();
for (int i = 0; i < array.Length; i++)
{
int count = 0;
for (int j = 0; j < array.Length; j++)
if (array[i] == array[j])
count++;
// Add to the hashset, if the add method returns true,
// it means the value was uniquely added, ergo you have not displayed yet
if (hashSet.Add(array[i]))
Console.WriteLine($"{array[i]} appears " + count + " times");
}
Full Demo Here
Or another approach is to use a Dictionary. The premise is to iterate over the array, try an add each item to the dictionary with TryAdd if it's already found increment the value
var dictionary = new Dictionary<int,int>();
foreach(var item in array)
if(!dictionary.TryAdd(item,1))
dictionary[item]++;
foreach(var item in dictionary)
Console.WriteLine($"{item.Key} appears {item.Value} times");
Full Demo Here
The first idea I had was the same of the comment from Jon Skeet, since the simplicity it implies.
The idea is to set null for the value we have already counted (matched).
From a developer point of view it is very simple and doesn't deviate too much from the OP's code.
Console.Write("Number of elements in the array: ");
int numberOfElements = int.Parse(Console.ReadLine());
int?[] array = new int?[numberOfElements];
for (int i = 0; i < numberOfElements; i++)
{
Console.Write($"Element no {i + 1}: ");
array[i] = int.Parse(Console.ReadLine());
}
for (int i = 0; i < array.Length; i++)
{
int count = 0;
int? current = array[i];
if (array[i] != null)
{
for (int j = 0; j < array.Length; j++)
{
if (current == array[j])
{
count++;
array[j] = null;
}
}
Console.WriteLine($"{current} appears " + count + " times");
}
}
int?[] defines a nullable value type. Therefore each item in the array can have either a null or int value - documentation here.
An approach using Dictionary with O(n) complexity.
Console.Write("Number of elements in the array: ");
int numberOfElements = int.Parse(Console.ReadLine());
var dictionary = new Dictionary<int, int>();
for (int i = 0; i < numberOfElements; i++)
{
Console.Write($"Element no {i + 1}: ");
var value = int.Parse(Console.ReadLine());
if (!dictionary.ContainsKey(value)) dictionary.Add(value, 0);
dictionary[value] = dictionary[value] + 1;
}
foreach (var item in dictionary)
{
Console.WriteLine($"{item.Key} appears {item.Value} times");
}
One simple way would be to swap your outer for loop with a foreach using a set to obtain distinct values.
So replace this:
for (int i = 0; i < array.Length; i++)
With this:
foreach (int i in new HashSet<int>(array))
And this:
if (array[i] == array[j])
With this:
if (i == array[j])
Other approach more suited for you would be too take only unique values from array, i.e.:
var unique = array.Distinct().ToArray();
for (int i = 0; i < unique.Length; i++)
{
int count = 0;
for (int j = 0; j < array.Length; j++)
{
if (array[i] == array[j])
{
count++;
}
}
Console.WriteLine($"{unique[i]} appears " + count + " times");
}
In the inner loop, try to check if there were already any occurrences of the current element until you exceed the outer index.
for(int i = 0; i < array.Length-1; i++)
{
int count = 1;
bool appeared = false;
for(int j = 0; j < array.Length; j++)
{
// until we are not at the same index as the outer loop
// check if we haven't already met the current element
if(j < i)
{
if (array[i] == array[j])
{
// set current value appearance to true
// to know if current element should be displayed
appeared = true;
// break the loop because there is no sense of continuing
// current look
break;
}
}
// if we are ahead of outer index
// check if there are occurences of the element
else if(j > i)
{
if (array[i] == array[j])
count++;
}
}
// don't print the current element if it has appeared before
if(!appeared)
Console.WriteLine($"{array[i]} appears {count} times");
}
I believe there should be a more optimal solution, as this one's time complexity is linear... You can think of some optimization. For example, you can store occurred elements in the array and check through the array at each iteration, so you don't need to start the inner loop from the beginning, but instead start it from the outer loop's position + 1 but it's also not the best solution.
P.S check out about string interpolation, because you don't need to concatenate strings when you use it.
You can also use Lookup here:
var sb = new StringBuilder();
foreach (var value in array.ToLookup(item => item))
{
sb.AppendLine($"{value.Key} appears " + value.Count() + " times");
}
Console.WriteLine(sb.ToString());

C# List start with value 1

When i use for (int i = 1; ..) skip the loop the first item.
How can i start with index 1 and dont skip any item?
private void buttonReadAndSort_Click(object sender, EventArgs e)
{
ReadFromFile rd = new ReadFromFile();
var fileList = rd.readFromFile();
for (int i = 0; i < fileList.Count; i++)
{
var item = (fileList[i]);
Console.WriteLine(item);
list.Add(item);
listBox1.Items.Add(item);
}
buttonReadAndSort.Enabled = false;
}
I guess you want to start with index 1 but access the item at index 0:
for (int i = 1; i <= fileList.Count; i++)
{
var item = fileList[i-1];
Console.WriteLine(item);
list.Add(item);
listBox1.Items.Add(item);
}
But you could also loop normally and add +1 where you need it 1 based:
for (int i = 0; i < fileList.Count; i++)
{
var item = fileList[i];
Console.WriteLine("item:{0} #{1}", item, i + 1);
list.Add(item);
listBox1.Items.Add(item);
}
List, like array, start at zero. Not sure why you would want it to start it at 1 and not skip any items. I do something like csvLinesPartNumber.Add("stuff") to add to the list and then I can get "stuff" from the particular index like so: csvLinesPartNumber[4]. For example, I am doing a while sqlreader dot read which will loop through the table with the particular ID. Then you can do another loop to get the data. Just make sure you put the index in the square brackets.

C# Write listView to txt?

I have problem with write listView to txt, my code write all columns (first and second) to txt.
I have this code:
using (StreamWriter sw = new StreamWriter("databaseEN.txt"))
{
foreach (ListViewItem item in listView1.Items)
{
sw.WriteLine(item.Text);
for (int i = 1; i < item.SubItems.Count; i++)
{
sw.WriteLine(item.SubItems[i].Text);
}
}
}
I need write first column not all column to my txt, how change this?
A ListViewItem contains many SubItems, which you can access from your item variable.
item.SubItems[0].Text;
This will get only the first column. You can also specify a column name as a string.
This is what I came up with. It works for me. It looks long because of the coments and the new lines added so it looks good in the text file when it gets saved.
// Save File Button
private void save_button_Click(object sender, EventArgs e)
{
System.IO.File.AppendAllText(#"C:\bbbb.txt", Environment.NewLine + Environment.NewLine);
// Columns NAMES
for (int c = 0; c < timeTable_listView.Columns.Count; c++)
{
System.IO.File.AppendAllText(#"C:\bbbb.txt", timeTable_listView.Columns[c].Text+"\t");
}
// Add new Line int the txt file
System.IO.File.AppendAllText(#"C:\bbbb.txt", Environment.NewLine + Environment.NewLine);
// Get all Items "loop All items"
for (int i = 0; i < timeTable_listView.Items.Count; i++)
{
// Loop all Sub Items of the Current Item "[i]"
for (int a = 0; a < timeTable_listView.Items[i].SubItems.Count; a++)
{
// Write the sub item "[a]" to the file with "tab betwen each item"
System.IO.File.AppendAllText(#"C:\bbbb.txt", timeTable_listView.Items[i].SubItems[a].Text + "\t");
}
// Add new Line "the new Row" starts at new line
System.IO.File.AppendAllText(#"C:\bbbb.txt", Environment.NewLine);
}
}
Iamege: Form
Image: TXT File
ONLY CODE:----------------------------------------------------------------
private void save_button_Click(object sender, EventArgs e)
{
System.IO.File.AppendAllText(#"C:\bbbb.txt", Environment.NewLine + Environment.NewLine);
for (int c = 0; c < timeTable_listView.Columns.Count; c++)
{
System.IO.File.AppendAllText(#"C:\bbbb.txt", timeTable_listView.Columns[c].Text+"\t");
}
System.IO.File.AppendAllText(#"C:\bbbb.txt", Environment.NewLine + Environment.NewLine);
for (int i = 0; i < timeTable_listView.Items.Count; i++)
{
for (int a = 0; a < timeTable_listView.Items[i].SubItems.Count; a++)
{
System.IO.File.AppendAllText(#"C:\bbbb.txt", timeTable_listView.Items[i].SubItems[a].Text + "\t");
}
System.IO.File.AppendAllText(#"C:\bbbb.txt", Environment.NewLine);
}
}
Delete this lines:
for (int i = 1; i < item.SubItems.Count; i++)
{
sw.WriteLine(item.SubItems[i].Text);
}
EDIT: Extracted from here http://msdn.microsoft.com/en-us/library/aa983553(v=vs.71).aspx
The Windows Forms ListView control can display additional text, or
subitems, for each item in the Details view. The first column displays
the item text, for example an employee number. The second, third, and
subsequent columns display the first, second, and subsequent
associated subitems.

Go through a checked listbox and check all items C#

I need to loop through a checked listbox, and for each of the items in it, I need to check them (basically like a "select all" function).
Is there a basic example you could give me to help me out please?
Use SetSelected and interate through all the Items
// Loop through and set all to selected.
for (int x = 0; x < listBox1.Items.Count; x++)
{
listBox1.SetSelected(x, true);
}
To check the items, use SetItemChecked
// Loop through and set all to checked.
for (int x = 0; x < listBox1.Items.Count; x++)
{
listBox1.SetItemChecked(x, true);
}
You can look through all the items as ListItems:
foreach (ListItem li in CheckBoxList1.Items)
{
li.Selected = true;
}

Categories