Force File Browser to Sort files by Name - c#

I have a button that opens a file browser and select multiple files, then adds them to a ListView.
How can I force the Browser Dialog Box to always sort the files by name before being added to the ListView?
Sometimes windows defaults to Date Modified or another sorting method besides Name.
Note: I have full file paths in a List, and just file names in the ListView.
private void btnInput_Click(object sender, RoutedEventArgs e)
{
// Open Select File Window
Microsoft.Win32.OpenFileDialog selectFiles = new Microsoft.Win32.OpenFileDialog();
selectFiles.Multiselect = true;
// Process Dialog Box
Nullable<bool> result = selectFiles.ShowDialog();
if (result == true)
{
// Add Path+Filename to List
foreach (String file in selectFiles.FileNames)
{
lstFilesPaths.Add(file);
}
// Add List Filename to ListView
lsvFiles.Items.Clear();
foreach (String name in fileList)
{
lsvFileNames.Items.Add(Path.GetFileName(name));
}
}
}

The filebrowser itself won't sort its results by filename, you will need to do that before using them.
Given lstFilesPaths is a List of strings you're saving the selected file paths to for use elsewhere, try this to sort the list by file name adding:
foreach (var name in lstFilesPaths.Select(f => Path.GetFileName(f)).OrderBy(s => s))
{
lsvFileNames.Items.Add(name);
}
Or, if you'd like both your list of file paths and the list view of file names sorted, try this:
// Add Path+Filename to List
lstFilesPaths.AddRange(selectFiles.FileNames.OrderBy(f => Path.GetFileName(f)));
// Add List Filename to ListView
lsvFiles.Items.Clear();
foreach (var name in lstFilesPaths.Select(f => Path.GetFileName(f)))
{
lsvFileNames.Items.Add(name);
}

try changing to:
lstFilePaths.AddRange(selectFiles.FileNames.OrderBy(x => x))
lsvFileNames.Items.Clear();
lstFilePaths.ForEach(x => lsvFileNames.Items.Add(Path.GetFileName(x)));

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.

Strip leading characters from a directory path in a listbox in C#

So i am attempting to teach myself C#, I have a program that I originally wrote in batch and am attempting to recreate in C# using WPF. I have a button that allows a user to set a directory, that directory selected is then displayed in a text box above a listbox which adds every subfolder, only first level, to the listbox. Now all this works fine but it writes out the entire directory path in the listbox. I have been trying to figure out how to strip the leading directory path off the list box entries for over an hour to no avail. Here is what I have so far:
private void btn_SetDirectory_Click(object sender, RoutedEventArgs e)
{
//Create a folder browser dialog and set the selected path to "steamPath"
var steamPath = new FolderBrowserDialog();
DialogResult result = steamPath.ShowDialog();
//Update the text box to reflect the selected folder path
txt_SteamDirectory.Text = steamPath.SelectedPath;
//Clear and update the list box after choosing a folder
lb_FromFolder.Items.Clear();
string folderName = steamPath.SelectedPath;
foreach (string f in Directory.GetDirectories(folderName))
{
lb_FromFolder.Items.Add(f);
}
}
Now I tried changing the last line to this, and it did not work it just crashed the program:
foreach (string f in Directory.GetDirectories(folderName))
{
lb_FromFolder.Items.Add(f.Substring(f.LastIndexOf("'\'")));
}
I am fairly certain that the LastIndexOf route is probably the right one but I am at a dead end. I apologize if this is a dumb question but this is my first attempt at using C#. Thanks in advance.
This can solve your issue
string folderName = steamPath.SelectedPath;
foreach (string f in Directory.GetDirectories(folderName))
{
// string[] strArr = f.Split('\\');
lb_FromFolder.Items.Add(f.Split('\\')[f.Split('\\').Length-1]);
}
You can use this code:
string folderName = steamPath.SelectedPath;
foreach (string f in Directory.GetDirectories(folderName))
{
lb_FromFolder.Items.Add(f.Remove(0,folderName.Length));
}

Get a list of files/directories in an open Explorer window in C#

I'm trying to pull out the list of files and directories listed in an open Explorer window (in the same order as they're displayed) so that I can look through it, then set focus to a particular item.
I found this code here that allows me to get the selected items, however I'm not sure if it's possible to use this approach to get all items:
List<string> SelectedFiles() {
string filename;
List<string> selected = new List<string>();
var shell = new Shell32.Shell();
foreach (SHDocVw.InternetExplorer window in new SHDocVw.ShellWindows()) {
filename = Path.GetFileNameWithoutExtension(window.FullName).ToLower();
if (filename.ToLowerInvariant() == "explorer") {
((Shell32.IShellFolderViewDual2)window.Document).SelectItem()
foreach (Shell32.FolderItem item in items) {
selected.Add(item.Path);
}
}
}
return selected;
}
It looks like this Shell32 approach would also allow me to select an item programmatically, which is the other part I'm trying to accomplish. Instead of SelectedItems(), I would call SelectItem(), though I'm not sure how to use that function.
Anyone know of a way to get the list of files/directories from an open Windows Explorer window (and ideally set focus to an item)? Perhaps a P/Invoke kind of thing?
I was able to modify that code snippet I found to list all files/directories instead of just the selected ones.
Here's what I ended up with:
List<string> FilesAndFolders() {
string filename;
List<string> explorerItems = new List<string>();
var shell = new Shell32.Shell();
foreach (SHDocVw.InternetExplorer window in new SHDocVw.ShellWindows()) {
filename = Path.GetFileNameWithoutExtension(window.FullName).ToLower();
if (filename.ToLowerInvariant() == "explorer") {
Shell32.Folder folder = ((Shell32.IShellFolderViewDual2)window.Document).Folder;
Shell32.FolderItems items = folder.Items();
foreach (Shell32.FolderItem item in items) {
explorerItems.Add(item.Path);
}
}
}
return explorerItems;
}
Edit:
To select an item, you call:
((Shell32.IShellFolderViewDual2)window.Document).SelectItem(item, 1);
where window is a SHDocVw.InternetExplorer, and item is a Shell32.FolderItem (from folder.Items() in the above example).
To deselect, it, pass in 0 instead of 1 as the second overload.

OpenFileDialog box with multiselect, .filenames receiving same name multiple times

I have a multi-select OpenFileDialog box (named GetFiles) that loops through all the selected files and displays their path in a listbox. Problem is, when all the files are selected and added, it displays the same filename. Here is all the code:
if (GetFile.ShowDialog() == DialogResult.OK)
foreach (string filename in GetFile.FileNames)
{
FileNameList.Items.Add(GetFile.FileName);
}
I feel like there is something really simple that I'm missing....any help will be greatly appreciated
Yes, you are adding the same filename each time using GetFile.FileName. You need to use your variable filename:
if (GetFile.ShowDialog() == DialogResult.OK)
foreach (string filename in GetFile.FileNames)
{
FileNameList.Items.Add(filename);
}
Yes, you're using GetFile.FileName when adding to the list rather than the enumerated value filename.
Try this instead:
if (GetFile.ShowDialog() == DialogResult.OK) {
foreach (string filename in GetFile.FileNames) {
FileNameList.Items.Add(filename);
}
}

Filling Listview & Imagelist selected item confusion c#

I new to programming and C# and seemed to have worked myself into a bit muddle with the above.
What i am trying to do is create a front end for the living room media pc nothing to fancy to start with as i understand this is a mamoth task for a total noobie like me.
Ive flapped about and am totally fine with launching external exe's,storing/loading resouces ect.. and been very happy with my results for my 2 week surfing.
So im starting off my project by just launching an emulator to start with and what i would like to do is scan a folder for zip files and image files and if it finds matching image and zip files it displays an image in a list view for each zip found.
So i populate my listboxes like this and get my 2 listboxes showing the stuff i want to see.
PopulateListBox(listBox1, "\\SomePath\\", "*.zip");
PopulateListBox(listBox2, "\\Images\\", "*.jpg");
private void PopulateListBox(ListBox lsb, string Folder, string FileType)
{
DirectoryInfo dinfo = new DirectoryInfo(Folder);
FileInfo[] Files = dinfo.GetFiles(FileType);
foreach (FileInfo file in Files)
{
lsb.Items.Add(file.Name);
}
}
So i now have my 2 listboxes and can see i have game1.zip and game1.jpg, great now i can populate my listview with the game1 image and launch the emulator he say's simple.
This is how i am currently populating the listview.
PopulateListView();
private void PopulateListView()
{
if (listBox1.Items.Contains("game1.zip"))
{
if (File.Exists("\\Images\\game1.jpg"))
{
imageList1.Images.Add(Image.FromFile("\\Images\\game1.jpg"));
listView1.Items.Add("", 0);
}
}
if (listBox1.Items.Contains("game2.zip"))
{
if (File.Exists("\\Images\\game2.jpg"))
{
imageList1.Images.Add(Image.FromFile("\\Images\\game2.jpg"));
listView1.Items.Add("", 1);
}
}
}
This is how i am currently launching and it works ok.
// launch item
private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (listView1.Items[0].Selected == true)
{
string rom = "\\" + listBox1.Items[0].ToString();
// Launch code in here
}
if (listView1.Items[1].Selected == true)
{
string rom = "\\" + listBox1.Items[1].ToString();
// Launch code in here
}
}
So what the problem you may ask ?
Instead of keep typing in all that info for each item i want to use some kind of statment if possible and i dont know what to search for which does not help.
The image name will allways match the zip name just need to loose the file extensions so to populate the listview somthing like this.
if (listbox1 item = listbox2 item)
{
add to imagelist and listview automaticly with same index
}
Then i want to be able to launch just using somthing like this.
private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
string rom = "\\" + listview.selected.item.tostring;
// Launch code in here
}
Hope im making sense im at my witts end.
Regards
Derek
If i understand correctly, you want to read, match and show programmatically all images and zips that are the same and when the user clicks a list view row to start the rom. This can be done as follows:
read all images - there is no need to check if the file exists, because if it does not, then GetFiles will not find it!
read all roms - same as above!
take all names that have both image and zip file (that are the same)
fill image list and list view at the same time
bind list view item with the correct image
store rom location
handle mouse click on row and fetch rom location
do something with rom file
The code:
public ListForm()
{
InitializeComponent();
// path to images and roms
const string location = #"d:\temp\roms\";
// bind image list with list view
listViewControl.SmallImageList = imageList;
// get all images without extension
var images = System.IO.Directory.GetFiles(location, "*.gif").Select(f => System.IO.Path.GetFileNameWithoutExtension(f)).ToList();
// get all roms without extension
var zips = System.IO.Directory.GetFiles(location, "*.zip").Select(f => System.IO.Path.GetFileNameWithoutExtension(f)).ToList();
// find all entries (images and zips) that have the same name
var matching = images.Intersect(zips);
var imageIndex = 0;
// fill image list and list view at the same time and store rom location
foreach (var match in matching)
{
// path to file without extension
var file = System.IO.Path.Combine(location, match);
// add image to image list
imageList.Images.Add(match, Bitmap.FromFile(string.Format("{0}.gif", file)));
// create list view item
var lvi = new ListViewItem(match);
// and set list view item image
lvi.ImageIndex = imageIndex;
// store rom location
lvi.Tag = string.Format("{0}.zip", file);
imageIndex++;
// and show
listViewControl.Items.Add(lvi);
}
}
private void listViewControl_MouseClick(object sender, MouseEventArgs e)
{
// when user clicks an item, fetch the rom location and go
var item = listViewControl.GetItemAt(e.X, e.Y);
if (item != null)
{
var pathToRom = item.Tag as string;
// do something with rom ...
}
}
There is no need to handle the image list and the list view separately. The output looks like:
you can Populate the images using the names from the listView:
private void PopulateListView()
{
foreach (string curr in listBox1.Items)
{
string changed = "\\Images\\" + curr.Replace(".zip", ".jpg");
if (File.Exists(changed))
{
imageList1.Images.Add(Image.FromFile(changed));
listView1.Items.Add("", 1);
}
}
}
and use the selected item in the MouseDoubleClick event
// launch item
private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
string selected = (string) listBox1.SelectedItem;
string rom = "\\" + selected;
// Launch code in here
}
If I'm understanding your problem correctly, you can switch out your tower of if statements with this:
var item = listView1.SelectedItem
string rom = "\\" + item.ToString()
// Launch code in here
And to populate it, you can change this:
if (listBox1.Items.Contains("game2.zip"))
{
if (File.Exists("\\Images\\game2.jpg"))
{
imageList1.Images.Add(Image.FromFile("\\Images\\game2.jpg"));
listView1.Items.Add("", 1);
}
}
To this:
List<string> files = new List<string> { "game1.zip", "game2.zip" };
var index = 0;
foreach (var file in files)
{
if (File.Exists("\\Images\\" + file))
{
imageList1.Images.Add(Image.FromFile("\\Images\\" + file.Replace(".zip", ".jpg")));
listView1.Items.Add("", index);
index++;
}
}

Categories