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++;
}
Related
I wish for my ListBox to update the old values with new values rather than simply adding more and more lines to the ListBox like it does at the moment. However, I'm not sure where to look to implement something that can handle this.
My current code looks like this:
private void DisplayText(string rawData)
{
textArduinoData.Text = rawData;
string[] sortedData = rawData.Split(';');
for (int i = 0; i < sortedData.Length; i++)
{
listPortData.Items.Add(sortedData[i].ToString());
}
}
Could someone please point me in the right direction to implementing this update feature? Any advice would be much appreciated.
You need to manage the process. It is easy in concept but depending on how much data is needed to be processed, it could get slow quickly. Steps
Create a specialized token class which implements to INotifyPropertyChanged.
Have an ObservableCollection hold the class items from #1. The observable collection notifies the ListBox when an item is added or removed. This will allow your code to add items one at a time. (Solves 1 problem)
To solve the next problem of data changing: Have a property named Text, on the class in #1 which will hold the data, provide a property change notification.
In the list box bind to the list of items created in step 1 and specify to bind to the Text. Use of a data template for the listbox will allow you to bind to the Text property of the list's instance.
Provide the heuristics/ smarts to read incoming data and find the associated data in the observable collection from step 2. When found change the Text property of the existing data to the new and the binding of that list item will change accordingly.
You could check if the ListBox contains the string using the IndexOf method and then update the existing string (or simply do nothing) or add a new one depending on whether you get an index other than the default value of -1 back:
private void DisplayText(string rawData)
{
textArduinoData.Text = rawData;
string[] sortedData = rawData.Split(';');
int index;
for (int i = 0; i < sortedData.Length; i++)
{
if ((index = listPortData.Items.IndexOf(sortedData[i])) == -1)
{
listPortData.Items.Add(sortedData[i]);
}
}
}
I have a drop down combo box that changes the image of a picture box. The images are stored in a resx file with an array that counts them, so that if I ever decide to add more, I need only to update the combo box, and add the images to the resx file. The problem I'm having is that when I update the image with the combo box, the images in the resx aren't in alphabetical order, but they do change the image on the picture box.
Here is my code
ResourceSet cardResourceSet = Properties.Resources.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
attributes = new Image[cardCount];
cardCount = 0;
foreach (DictionaryEntry entry in cardResourceSet)
{
string resourceKey = (string)entry.Key;
object resource = entry.Value;
cardCount++;
}
attributes = new Image[cardCount];
cardCount = 0;
foreach (DictionaryEntry entry in cardResourceSet)
{
attributes[cardCount] = (Image)entry.Value;
cardCount++;
}
if (attributeBox.SelectedIndex != -1)
{
this.cardImage.Image = attributes[attributeBox.SelectedIndex];
}
How can I go about making it sort the resources in the resx alphabetically?
The return type of GetResourceSet, ResourceSet, implements IEnumerable, so you should be able to run some LINQ ordering on it:
foreach (var entry in cardResourceSet.Cast<DictionaryEntry>().OrderBy(de => de.Key))
{
}
Since you're iterating over it twice (though I'm not really sure of the point of the first for-loop, unless there's other code), you may want to assign the sorted results to a separate variable:
var sortedCardResourceSet.Cast<DictionaryEntry>().OrderBy(de => de.Key).ToList();
foreach (var entry in sortedCardResourceSet)
{
...
}
...
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.
My requirement is to hide specific rows in a ListView. Since there is no inbuilt functionality I was using the ListView_DrawItem Event to hide the specific rows. I was able to hide the rows but the issue is there is a balnk space coming if i add a row post to the hidden row.
Please find the below code:
ListViewItem LVI = listView1.Items.Add("1");
LVI.SubItems.Add("Srikanth");
ListViewItem LVI1 = listView1.Items.Add("2");
LVI1.SubItems.Add("Suresh");
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
if (e.Item.Text != "2")
{
e.DrawDefault = true;
}
}
Output Looks Like
1 Srikanth
3 Sandy
Would like to remove the space b/w 1 & 3 record
Any help is appreciated
You are not really hiding the items, that is plain to see. Instead, you are offering to draw them yourself, and passing some off to default rendering. The items are there regardless.
My approach would be to manipulate the collection, adding only those items that the list box needs to deal with.
Depending on the data you have at hand, keep a local copy of the full list, in order, such as in a generic List<YourDataClass>. Also, keep a list of 'hidden' indexes.
Respect the order of List<T> and loop across it, only adding new ListViewItem objects for those indexes not present in the 'hidden' list.
private List<String[]> _listItems = new List<String[]>();
private List<Int32> _hiddenIndexes = new List<Int32>();
private void UpdateCollection()
{
listBox.Items.Clear();
for (Int32 i = 0; i < _listItems.Count; i++)
{
if (!_hiddenIndexes.Contains(i))
listBox.Items.Add(new ListBoxItem(_listItems[i]));
}
}
Beware that if this happens to be a list with a very large number of items, it might not be the most efficient approach.
I have a listview with few items. I am using foreach loop to check if there is a match. The code I am using looks like this:
foreach (ListViewItem test in listView1.Items)
{
if (test.SubItems[1].ToString() == item.SubItems[1].ToString())
{
test.Tag = item.Tag;
}
}
What I am trying to do is, check the 2nd index and if there is a match replace the old item 'test' with the new one 'item'.
Apparently there is no change in the listview. Is the way I am replacing the object wrong?
you can clone the item and assign directly to the list view item. but you need to change foreach loop to for loop.
for (int i = 0; i < listView1.Items.Count; i++)
{
if (listView1.Items[i].SubItems[1].ToString() == item.SubItems[1].ToString())
{
listView1.Items[i] = (ListViewItem)item.Clone();
}
}
You have updated the Tag only. You need to change test.SubItems[0], test.SubItems[1],... to see the changes.
Or you could remove old item and insert new item by using listView1.Items.Remove(...) or listView1.Items.RemoveAt(...) and listView1.Items.Insert(...). But if you need to pay account of performance you should use the first algorithm (changing test.SubItems[i]).