GeneratorPosition Error on Bound Observable Collection - c#

I am using a Transitionals Slideshow control which has an observable collection of strings bound to the itemsource. These strings are the file paths to each picture in the slidehow. When I first load the WPF app, it runs this method correctly (using a directory path to generate the PicSlideShowCollection):
public void SelectImages(string path)
{
// Validate
if (string.IsNullOrEmpty(path)) throw new ArgumentException("path");
PicSlideShowCollection.Clear();
// Get directory info for specified path
DirectoryInfo di = new DirectoryInfo(path);
// Image mask
string[] extensions = new string[] { "*.jpg", "*.png", "*.gif", "*.bmp" };
// Search for all
foreach (string extension in extensions)
{
foreach (FileInfo fi in di.GetFiles(extension.ToLower()))
{
PicSlideShowCollection.Add(fi.FullName);
}
}
}
However, I have a button that allows the user to change the directory of images to use in the slideshow and re-runs the above method. When that is executed, I get this error:
GeneratorPosition '-1,1' passed to Remove does not have Offset equal
to 0.
This occurs on the PicSlideShowCollection.Clear() instruction.
If I comment that instruction, the new directory images get ADDED TO the original directory pictures which is NOT what I want.
I know this has to do with the PicSlideShowCollection being used as an item source to the Slide show control, but I need to know how I can prevent this error from occuring.
Thank you!

Slideshow.AutoAdvance = false;
Slideshow.SelcetedIndex=-1;
var count=PicSlideShowCollection.Count;
forearch(var item in newsources)
{
PicSlideShowCollection.Add(item);
}
while(count--)
PicSlideShowCollection.RemoveAt(0);
Slideshow.SelcetedIndex=0;

I can't explain why this error occurs. GeneratorPosition is used by the ItemContainerGenerator of an ItemsControl, which should simply work when you bind to its ItemsSource property and add or remove items to/from the source collection. Clearing the source collection is of course also a valid operation.
A possible workaround for the problem would be to reset the ItemsSource each time you switch to another image directory. So instead of clearing the existing collection
PicSlideShowCollection.Clear();
create a new collection and set ItemsSource to the new collection:
PicSlideShowCollection = new ObservableCollection<string>();
slideShowControl.ItemsSource = PicSlideShowCollection;

Related

How to fix ListView.LargeImageList showing images twice

I am working on a piece of software, which compares memes and helps users organize memes on their computer. As a part of this I am using Windows.Forms to build a UI. This UI lets the user add folders to be checked for images, which can be compared to a set of known meme templates.
My issue arises when I try to show the user the found images. To do this I am using a ListView and the property LargeImageList to contain a tuple of the image and the name of the image file.
Here is the piece of code in question:
private void button1_Click(object sender, EventArgs e)
{
int i = 0;
var ic = new ImageCollection();
var fbd = new FolderBrowserDialog();
fbd.Description = "Select meme folder or image.";
if (fbd.ShowDialog() == DialogResult.OK)
{
string[] files = Directory.GetFiles(fbd.SelectedPath);
foreach (var file in files)
{
if (!ic.CheckIfImage(file)) continue;
imageList1.Images.Add(Image.FromFile(file));
}
foreach (var file in files)
{
listView1.Items.Add($"{Path.GetFileNameWithoutExtension(file)}", i++);
}
}
}
This is an example of what the user sees when they first load in a folder. When the user tries to load in another folder this happens. It shows the images from the first folder, with the names of the image files from the second folder.
Does anyone know a fix for this issue? I have tried a variety of options in order to get around the issue. All from trying to clear the ImageList used to contain the images, to trying my hand at controlling when the ListView updates. None of this has worked. I have also tried googling the issue, but with no luck of finding a fix.
Thank you in advance.
If you want to show the content of a single folder at the time, then dispose of the objects in your ImageList.
If you instead want to show the content of more than one folder, you need to specify the new index of the image added. You're instead adding a new Item in the ListView using the same index reference:
int i = 0;
//(...)
listView1.Items.Add($"{Path.GetFileNameWithoutExtension(file)}", i++);
The indexer (i) always starts from 0, thus the ListView Item will use the images in your Imagelist starting from the Image at Index[0] each time. The new images won't ever be shown.
You can use the ImageList.Images.Count value, representing the number of Images already added to the ImageList, as base and increment the indexer starting from this value:
private void button1_Click(object sender, EventArgs e)
{
int i = imageList1.Images.Count;
var ic = new ImageCollection();
var fbd = new FolderBrowserDialog();
fbd.Description = "Select meme folder or image.";
if (fbd.ShowDialog() == DialogResult.OK)
{
foreach (var file in Directory.GetFiles(fbd.SelectedPath))
{
if (!ic.CheckIfImage(file)) continue;
imageList1.Images.Add(new Bitmap(file, true));
listView1.Items.Add($"{Path.GetFileNameWithoutExtension(file)}", i++);
}
}
}
If you allow to remove an Image from the ListView, you should also remove it from the ImageList: this implies that you need to re-index all the ListView Items starting from the Item that follows the one removed.
Remember to dispose of the Images you remove from the ImageList.

Combobox crashes when selecting item with keyboard

I have a problem with the code below, basically what is does is read from a path where files with extension .config are stored, it reads the names of the files without extension and displays them all in a combobox. That works fine and if you click on the down arrow and select a name it actually does what it's supposed to, however, once I have selected an item from the dropdown with the mouse and I go back and start typing inside the combobox my application crashes throwing a exception.
I've tried adding a try-catch-finally but it keeps throwing the same error. Could it be the loop that is causing my application to crash once I start typing in the combobox?
p.d. If I just use the mouse to select an item from the dropdown menu my application works fine but once I've selected an item with the mouse and use the keyboard to type another item name inside the combobox my app crashes. Any pointers would be helpful.
// Gets all the file names from the path assigned to templatePath
// and assigns it to the string array fname
string[] fname = Directory.GetFiles(templatePath);
// Begin sorting through the file names assigned to the string array fname
foreach (string file in fname)
{
// Remove the extension from the file names and compare the list with
// the dropdown selected item
if (System.IO.Path.GetFileNameWithoutExtension(file) == cbTemplates.SelectedItem.ToString())
{
// StreamReader gets the contents from the found file and assigns
// them to the labels
using (var obj = new StreamReader(File.OpenRead(file)))
{
lbl1.Content = obj.ReadLine();
lbl2.Content = obj.ReadLine();
lbl3.Content = obj.ReadLine();
lbl4.Content = obj.ReadLine();
lbl5.Content = obj.ReadLine();
lbl6.Content = obj.ReadLine();
lbl7.Content = obj.ReadLine();
lbl8.Content = obj.ReadLine();
lbl9.Content = obj.ReadLine();
lbl10.Content = obj.ReadLine();
obj.Dispose();
}
}
}
My guess is this is probably causing the error:
cbTemplates.SelectedItem.ToString()
When you start typing in the combobox, the SelectedItem becomes null.
You should test whether the cbTemplates.SelectedItem is null before attempting to invoke ToString() on it. And if you're trying to match on the text of the combo-box, you might try using cbTemplates.Text instead.
And as others commented on your question, you don't need to call Dispose inside using and you should consider the possibility that the file might not contain 10 lines..

Listbox refreshing and binding wp7

I actually display on my Listbox this list of item that i retrive from XML . When I click on an Item i am going back to the same method and creating a new list to display with different items.
I am wondering why it's not clearing the previous list.
This is the code I use, I can't figure this out ..
if (e.Error == null)
{
// Retrieving the subfolders
XDocument xdoc = XDocument.Parse(e.Result, LoadOptions.None);
XNamespace aNamespace = XNamespace.Get("http://schemas.datacontract.org/2004/07/System.IO");
var folders = from query in xdoc.Descendants(aNamespace.GetName("DirectoryInfo"))
select new Folder
{
Name = (string)query.Element("OriginalPath"),
};
ObservableCollection<Folder> LFolders = new ObservableCollection<Folder>();
foreach (Folder f in folders)
{
LFolders.Add(f);
}
listBox1.ItemsSource = LFolders;
listBox1.SelectionChanged += new SelectionChangedEventHandler(listBox1_SelectionChanged);
}
Two suggestions:
Consider using the MVVM pattern and then storing and updating your ObservableCollection on the view model instead.
Set the SelectionChanged event in XAML instead of where you're setting it now. For every call to this method you're appending an additional event handler to your listBox1.
If you set the Itemssource to null before you set the new value, I believe that will work. Also, you can try making LFolders a class variable. When you begin the method, clear the collection and then add to it. THe observable collection that is bound to the listbox will take care of updating the listbox.

TreeView Not Displaying Images from ImageList

I have a TreeView that displays CheckBoxes:
I want to check if a given directory contains an ".mdf" database and if it does, check whether it is attached on the selected server instance. If the database is attached I display an image against that node, and a different image if it is not attached. Note: The images are .png format, size 32x32...
I populate an ImageList from Properties.Resources
mainImageList = new ImageList();
mainImageList.Images.Add(Properties.Resources.Database);
mainImageList.Images.Add(Properties.Resources.DatabaseGrey);
I then loop through the tree and add the relevant image
public static void RecursiveAddImage(TreeNode treeNode, List<string> attachedList)
{
if (String.Compare(Path.GetExtension(treeNode.Text), ".mdf", true) == 0)
{
string databaseName = treeNode.Text.Replace(".mdf", String.Empty);
if (attachedList.Contains(databaseName))
{
treeNode.ImageIndex = 0;
treeNode.SelectedImageIndex = 0;
}
else
{
treeNode.ImageIndex = 1;
treeNode.SelectedImageIndex = 1;
}
}
foreach (TreeNode node in treeNode.Nodes)
RecursiveAddImage(node, attachedList);
}
The above code goes through the loop with no complaints, finds ".mdf"s and seems to add the relevant ImageIndexes but these do not show up in the TreeView. What am I doing wrong here and can I add the ImageList at design time (something I also can't seem to do)?
I have read several posts and ofcourse the MSDN documantation but I still can't seem to get it working. Any help as always, is much appreciated.
Make sure the TreeView control has the ImageList property set to the correct ImageList reference:
mainImageList = new ImageList();
mainImageList.Images.Add(Properties.Resources.Database);
mainImageList.Images.Add(Properties.Resources.DatabaseGrey);
treeView1.ImageList = mainImageList;
TreeNode.StateImageIndex= 0; would set the imagelist images. Make sure the imagelist is binded to Treeview control as mentioned above.

C# listView check for repeated "fileName" entries

I am new to C#
I just want to ask if is it possible to check against a SUBItem in a listview for repeated values before i do a ADD() method??
Lets say i have a listview and i can add/delete items
I can have numerous items and subitems
I would like to perform a check before adding the file that i'm opening into the listview
The file that I'm going to put into would be, name of a file, eg example.txt
And if this file exists in the subitem, i will not add into the listview
Does anyone have any idea on how to check a subitem value against the value that I'm going to add into?
TIA
Well, you can iterate through the Items property of the ListView, and then the Subitems property for each item and finally check against the subitem's Text property.
The other option is to store the already added items in a List, and check if it already contains that item you want to add.
Edit: as requested, added sample code below.
private bool _CheckFileName(string fileName)
{
foreach(ListViewItem item in this.myListView.Items)
{
// this is the code when all your subitems are file names - if an item contains only one subitem which is a filename,
// then you can just against that subitem, which is better in terms of performance
foreach(ListViewItem.ListViewSubItem subItem in item.SubItems)
{
// you might want to ignore the letter case
if(String.Equals(fileName, subItem.Text))
{
return false;
}
}
}
return true;
}
using(var ofd = new OpenFileDialog())
{
// ... setup the dialog ...
if(ofd.ShowDialog() == DialogResult.Cancel)
{
// cancel
return;
}
// note that FileOpenDialog.FileName will give you the absolute path of the file; if you want only the file name, you should use Path.GetFileName()
if(!_CheckFileName(ofd.FileName))
{
// file already added
return;
}
// we're cool...
}
I didn't test the code so it is possible that I have some typos, if so, please add a comment and I'll fix it (though perhaps it would be better if you tried to figure it out yourself first :)).
You could create a helper class that contains information about each item. For each ListViewItem you create a new instance of this class and set ListViewItem.Tag to this instance.
You'd only have to iterate over all the items, get the helper object for the item and compare with that helper object.

Categories