Initializing ListView, why can't I do this? - c#

As an old C++ programmer I am struggling with some C# issues. I want to reduce the redundancy in setting up a ListView. So I tried the code below. I get a null reference error, but I do not understand why. The compiler has no problem with me creating an array of ListViewItems, but I don't see how to use them.
Thanks, Russ
ListViewItem [] items = new ListViewItem [12];
for (int i=0; i < 12; ++i) {
items [i].Text = string.Format ("F{0}", i+1);
}

You're allocating memory for an Array of 12 ListViewItems, but you haven't created the ListViewItem:
Instead, try something like the following:
List<ListViewItem> items = new List<ListViewItem>();
for (int i = 0; i < 12; i++) {
items.Add( //using the List.Add() method to add an item
new ListViewItem
{
Text = string.Format ("F{0}", i+1); //Object Initialization syntax to add an item after construction
});
}
This will create a List (an expandable collection); create a new ListViewItem in a loop, give that ListViewItem the text you want it to have, and then add that item to the List.

It seems that you're receiving the null reference because you're trying to set a property(Text) on something that wasn't initialized (ListViewItem[i]).
Try this:
ListViewItem [] items = new ListViewItem [12];
for (var i = 0; i < items.Length; ++i) {
items[i] = new ListViewItem{Text = string.Format ("F{0}", i+1)};
}

Related

Changing an FSharpList in C#

FSharpList<FSharpList<int>> newImageList;
FSharpList<int> row;
for(int i = 0; i < CurrentImage.Header.Height)
{
row = PPMImageLibrary.GrayscaleImage(CurrentImage.ImageListData);
newImageList.Head = row;
}
Above I'm trying to take a int list list and set each index to row which is a int list. Obviously I can't do it with .Head, and if I could it would only change the first index. I'm wondering how I could possibly make this work, I'm having a hard time getting any index of newImageList in the first place.
FSharpList is an immutable list. Therefore you cannot assign its Head and Tail properties something. However, you can try adding your FSharp list into a generic C# List or any collection that inherits an IEnumerable. For example from your code:
List<int> newImageList = new List<int>();
for(int i = 0; i < CurrentImage.Header.Height)
{
newImageList.AddRange(PPMImageLibrary.GrayscaleImage(CurrentImage.ImageListData)); // I am assuming your GrayscaleImage method might return multiple records.
}
I hope this helps.

ObjectListView add images to items/objects

I'm using the ObjectListViewand am trying to add images to my items. I got it to work by looping through all the items and then manually editing the image index per item. I would like to know if this is possible when adding the items. This is the code I have at the moment:
Adding the items
for (int i = 0; i < listName.Count; i++)
{
games newObject = new games(listName[i], "?");
lstvwGames.AddObject(newObject);
}
Adding the images
foreach (string icon in listIcon)
{
imglstGames.Images.Add(LoadImage(icon)); // Download, then convert to bitmap
}
for (int i = 0; i < lstvwGames.Items.Count; i++)
{
ListViewItem item = lstvwGames.Items[i];
item.ImageIndex = i;
}
It is not entirely clear to me what exactly you try to achieve, but there are several ways to "assign" an image to a row. Note that you probably have to set
myOlv.OwnerDraw = true;
which can also be set from the designer.
If you have a specific image for each of your model objects, its probably best to assign that image directly to your object and make it accessible through a property (myObject.Image for example). Then you can use the ImageAspectName property of any row to specify that property name and the OLV should fetch the image from there.
myColumn.ImageAspectName = "Image";
Another way to do it is using the ImageGetter of a row. This is more efficient if several of your objects use the same image, because you can fetch the image from anywhere you want or even use the assigned ImageList from the OLV by just returning an index.
indexColumn.ImageGetter += delegate(object rowObject) {
// this would essentially be the same as using the ImageAspectName
return ((Item)rowObject).Image;
};
As pointed out, the ImageGetter can also return an index with respect to the ObjectListView's assigned ImageList:
indexColumn.ImageGetter += delegate(object rowObject) {
int imageListIndex = 0;
// some logic here
// decide which image to use based on rowObject properties or any other criteria
return imageListIndex;
};
This would be the way to reuse images for multiple objects.
Both your approach and the one I show below will have problems if the list is ever sorted as sorting will change the order of the objects in the list. But really all you have to do is keep track of your object count in your foreach loop.
int Count = 0;
foreach (string icon in listIcon)
{
var LoadedImage = LoadImage(icon);
LoadedImage.ImageIndex = Count;
imglstGames.Images.Add(LoadedImage); // Download, then convert to bitmap
Count++;
}

Rows error help in listview function

Here is the code I am using.
foreach (DataRow row in data.Rows)
{
ListViewItem lst = default(ListViewItem);
lst = lvw.Items.Add(row(0)); // My error is on row
for (int i = 1; i <= data.Columns.Count - 1; i++)
{
lst.SubItems.Add(row(i));
}
}
Now, what I'm doing or trying to do is actually add database items onto my listview. However, I can't seem to get my rows onto my list view. I get a syntax error:
'Rows' is a 'variable' but is used like a 'method'.
I have been struggling with this winform for a couple days and my coding has stopped dead at this point. I have tried changing the parenthesis. Here is the whole function. I got it from the internet in vb.net and ran the code it worked. I then configured that code for my application in vb.net that worked too, now after converting to c# and it doesn't work which is my problem. I went through all the code(I am new to c# like relatively) and fixed most of it to work for my application except the row error
private void ShowDataInLvw(DataTable data, ListView lvw)
{
lvw.View = View.Details;
lvw.GridLines = true;
lvw.Columns.Clear();
lvw.Items.Clear();
foreach (DataColumn col in data.Columns)
{
lvw.Columns.Add(col.ToString());
}
foreach (DataRow row in data.Rows)
{
ListViewItem lst = default(ListViewItem);
lst = lvw.Items.Add(row(0));
for (int i = 1; i <= data.Columns.Count - 1; i++)
{
lst.SubItems.Add(row(i));
}
}
}
In C#, to get to an index of a collection, you need to use [ ] (whereas VB uses ( )). Refer to this specifically for DataRows.
Thus, your code should look like:
lst = lvw.Items.Add(row[0]);
And
lst.SubItems.Add(row[i])
On a side note, you may want to read up on the use of the default keyword.
EDIT:
Here's a complete listing (without spoon-feeding much), after noticing that your code won't actually work and assuming you really intend to do as described:
foreach (DataRow row in data.Rows)
{
ListViewItem lst = default(ListViewItem);
for (int i = 0; i <= data.Columns.Count - 1; i++)
{
if (i == 0)
lst = new ListViewItem(row[0].ToString());
else
lst.SubItems.Add(row[i].ToString());
}
lvw.Items.Add(lst);
}
Notice a few things:
The instantiation of lst has been changed.
The lvw will add the lst along with its subitems.
The addition will occur only after the subitems have been created.
Disclaimer: I haven't tested the code, but the idea is there.
Have you tried:?
lst = lvw.Items.Add(row[0]);
lst.SubItems.Add(row[I]);

Prevent listview from adding blank subitem

I have a listview in which the columns are dynamically created depending on the number of available subjects. When I create a new ListViewItem it automatically adds a blank subitem to the listview. Since the columns are dynamically created, the subitems are displaced. This is how I have done it.
foreach(int id in stud)
{
ListViewItem gtb = new ListViewItem();
foreach(int sname in subj)
{
gtb.SubItems.Add(value1);
gtb.SubItems.Add(value2);
gtb.SubItems.Add(value3);
}
gtb.SubItems.Add(value4);
listView1.Items.AddRange(new ListViewItem[] { gtb });
}
I know that adding the value1 to new ListViewItem(value1) would fix this but i have another subitem which is outside of the foreach loop. How can I fix this?
Add an 'if' statement that will check the length of each value then if the length is greater than zero you add the item to 'gtb'.
Create a String[], use it to collect your subitems, then create a new ListViewItem using that:
String[] subItems = new String[subj.Count + 1]; //add however many extras you need in place of 1
for (int j = 0; j < subj.Count; j++)
subItems[j] = subj[j];
//add whatever else to the array you want...
listView1.Items.Add(new ListViewItem(subItems));
I tried manually adding a new column which has a 0 width and it works just fine.

Find selected WPF Listbox entries

I've been trying iterate through the selected items of a listbox in WPF, with the following code;
try
{
for (int i = 0; i < mylistbox.SelectedItems.Count; i++)
{
ListItem li = (ListItem)mylistbox.SelectedItems[i];
string listitemcontents_str = li.ToString();
}
}
catch(Exception e)
{
// Error appears here
string error = e.ToString();
}
However I receive an invalid cast exception;
System.InvalidCastException: Unable to cast object of type 'mylist' to type 'System.Windows.Documents.ListItem'.
Is there a way around this?
I prefer to do it using data binding:
Sync SelectedItems in a muliselect listbox with a collection in ViewModel
for (int i = 0; i < mylistbox.SelectedItems.Count; i++)
{
List**Box**Item li = (List**Box**Item)mylistbox.SelectedItems[i];
string listitemcontents_str = li.ToString();
}
This should work:
for (int i = 0; i < mylistbox.SelectedItems.Count; i++)
{
var li = mylistbox.SelectedItems[i];
string listitemcontents_str = li.ToString();
}
A way I found was to assign the listbox onto an object then cast this onto a DataRowView. Seems to work and I can get access to the fields inside, by their respective column names.
object selected = mylistbox.SelectedItem;
DataRow row = ((DataRowView)selected).Row;
string thecontents = row["columnname"].ToString().TrimEnd();
You are confusing ListItem with ListBoxItem.
If you do nothing special, a ListBox will create ListBoxItem containers for the data you bind to it. ListItem is used inside FlowDocument and is basically a numbered or bulleted point in a document.
That said, data binding would be better. If you were using data binding, SelectedItems would not be a ListBoxItem but would be your actual data item that was bound. You can cast this to the appropriate type and use it.
The listbox adds it's items as a collection of objects, so it can't cast it to ListItem.
So for your purpose , you can do as following :
for (int i = 0; i < mylistbox.SelectedItems.Count; i++)
{
string listitemcontents_str = mylistbox.SelectedItems[i].ToString();
}
If you really want to use ListBoxItem , please add these items to your listbox e.g.
ListBoxItem li = new ListBoxItem();
li.Content = "Hello";
mylistbox.Items.Add(li);
then you can do what you want without Invalid cast exception:
for (int i = 0; i < mylistbox.SelectedItems.Count; i++)
{
ListBoxItem li = (ListBoxItem)mylistbox.SelectedItems[i];
string s = li.ToString();
}

Categories

Resources