How do I Use OpenFileDialog to select files or paths - c#

I am writing a WPF / C# application, and would like to enable a user to select one (or multiple) files, or one (or multiple) folders, without having to select which option they use initially, but intentionally. In my opinion, the best way to acchieve this goal would be to have a standard FolderBrowserDialog, and as long as the user does not seelct a file, but browses to a path, clicking the open button should select that path.
Practically, this solution does not work, because OpenFileDialog does not allow empty selections, you can hit "open", but nothing will happen. There is one workaround descriped here which allows to enter a fake name like "Selected Folder." as filename. which can afterwards be filtered out, which is a workaround, but not a nice one:
http://www.codeproject.com/Articles/44914/Select-file-or-folder-from-the-same-dialog
This solution has two important weaknesses:
1.) you will have to filter for the fake name
2.) if you paste a filename manually, or select a file first, and then switch the selection to a folder instead, the fake name is not inserted automatically.
of course I am aware there is something like FolderBrowserDialog, which I omit using even if I only wanted to select folders and not files. The reason: this dialog has no possibility to paste paths from clipboard, and I find it annoying to navigate all the way, I rather copy paths from somewhere and paste them, which works perfectly fine in OpenFileDialog, but not in FolderBrowserDialog. Besides, FolderBrowserDialog does not allow to select files and folders.
I have googled a lot, but do not find satisfying solutions, although I am sure many people must obviously face this problem.
As mentioned, the most elegant way for me would be to make the OpenFileDialog simply allow empty Filename boxes when clicking Open - any way to acchieve this?
Thanks alot.

Letting a user select a directory OR a file using the same dialog is not practical nor intuitively possible.
However, if you want a solution for selecting a Folder, here it is :
If you don't want to create a custom dialog but still prefer a 100% WPF way and don't want to use separate DDLs, additional dependencies or outdated APIs, I came up with a very simple hack using WPF's Save As dialog for actually selecting a directory.
No using directive needed, you may simply copy-paste the code below !
It should still be very user-friendly and most people will never notice.
The idea comes from the fact that we can change the title of that dialog, hide files, and work around the resulting filename quite easily.
It is a big hack for sure, but maybe it will do the job just fine for your usage...
In this example I have a textbox object to contain the resulting path, but you may remove the related lines and use a return value if you wish...
// Create a "Save As" dialog for selecting a directory (HACK)
var dialog = new Microsoft.Win32.SaveFileDialog();
dialog.InitialDirectory = textbox.Text; // Use current value for initial dir
dialog.Title = "Select a Directory"; // instead of default "Save As"
dialog.Filter = "Directory|*.this.directory"; // Prevents displaying files
dialog.FileName = "select"; // Filename will then be "select.this.directory"
if (dialog.ShowDialog() == true) {
string path = dialog.FileName;
// Remove fake filename from resulting path
path = path.Replace("\\select.this.directory", "");
path = path.Replace(".this.directory", "");
// If user has changed the filename, create the new directory
if (!System.IO.Directory.Exists(path)) {
System.IO.Directory.CreateDirectory(path);
}
// Our final value is in path
textbox.Text = path;
}
The only issues with this hack are :
Acknowledge button still says "Save" instead of something like "Select directory", but in a case like mines I "Save" the directory selection so it still works...
Input field still says "File name" instead of "Directory name", but we can say that a directory is a type of file...
There is still a "Save as type" dropdown, but its value says "Directory (*.this.directory)", and the user cannot change it for something else, works for me...
Most people won't notice these, although I would definitely prefer using an official WPF way if microsoft would get their heads out of their asses, but until they do, that's my temporary fix.

Related

C# OpenFileDialog multiple filename filters including exclude

I have a requirement to allow users to open a specific file for processing. The open file dialog is currently
OpenFileDialog ofg = new OpenFileDialog
{
FileName = "BaseFileName*",
Filter = "CSV File (*.CSV)|*.csv",
Multiselect = false,
InitialDirectory = #"N:\Downloads"
};
However the process adds a suffix of _Processed along with timestamp data to the filename and I want to exclude these renamed files the next time the OpenFileDialog is used to prevent the user trying to reprocess the same file.
I have to leave the original files where they are for internal audit reasons.
So I need an additional filename filter of not equal to "_Processed".
Is there any way to do this with OpenFileDialog or does anyone know of a custom c#/.net component that can do this?
You are asking to omit specific items from the file dialog view.
According to MSDN, this is no longer possible as of Windows 7, but was possible previously.
The C# file dialogs (both WPF and WinForms) use the IFileDialog API.
Here is the function that could have made this work, but is no longer supported:
https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfilter
As it is, you are stuck with checking the file for correctness after the user has already selected it and confirmed it with OK.
You can help the situation a little bit: If you enjoy pain, then you can copy the whole IFileDialog COM interop code from the .NET source code, and implement IFileDialogEvents. This way, when the user clicks "OK", you can deny the selection and display an error before the dialog closes, leaving the dialog open so the user can select a different file.
If you are sane and you don't want to do that, then you'll have to open the dialog again after the verification fails.
The easy way is just saving the processed data with another extension e.g. "BaseFileName_Processed_20105640640.cvs1", that way you keep the data and your file dialog will not show this file.
Another way could be to call the OpenFileDialog() in an if statement (and compare the return to DialogResult.OK), then split the file name for {'_','.'}, then run a loop to count the occurrences of the word Processed( >0), and possibly as a safety check determine whether a timestamp is present in one of the split strings. Finally, reload the FileOpenDialog in the same folder when the wrong file was selected.

How can I code defensively against potential unorthodox hard drive letters?

I can set a SaveFileDialog's InitialDirectory property to where my app will usually be installed like so:
saveFileDialog1.InitialDirectory = #"C:\Program Files\Waltons\Mountains";
...but as "there is one in every crowd," some may use a drive letter other than C for their hard drive? How can I set the InitialDirectory to whichever drive letter the user has specified?
UPDATE
I tried Alexei's code (had to change "Concat" to "Combine" and remove a superfluous ")":
saveFileDialog1.InitialDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Programs), #"Waltons\Mountains");
DialogResult result = saveFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
// TODO: Finish
}
...but it does not open C:\Program Files\Waltons\Mountains
UPDATE 2
Saeb's suggestion seems to work, as the save file dialog opens in C:\Waltons\Mountains\bin\Debug
...which I hope/reckon would correspond to C:\Waltons on the user's machine (or D:\Waltons or Z:\Waltons or whatever).
I would have to append the "\Maps" I guess for the user - check that it's not running in Visual Studio or something and append that in that event.
Location that is writable by normal user would be better default location for save dialog. I.e. "my documents" via Environment.GetFolderPath passing one of Environment.SpecialFolder values:
var pathToMyDocuments = Environment.GetFolderPath(Environment.SpecialFolder.Personal));
If you need location where your program installed by default like program files
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "MyFolder");
or if you need path relative to program check How can I get the application's path in a .NET console application?.
Note that locations above are not writable by normal users and even admin unless you turn off UAC or explicitly "run as administrator" or change default permissions on these folders (either of approaches to bypass default permission have its drawbacks and one should perform serious security review if allowing regular users to write in programs/system folders).
Don't use hardcoded driver letters. Find the path in runtime. e.g.:
saveFileDialog1.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
You can use the environment variable systemroot to get the drive. Try opening a cmd prompt and entering set to see a list of all the environment variables avaliable and then use System.Envrionment.GetEnvironmentVariable ("systemdrive") and combine that with the rest of your path.

FileDialog filter not updating when changing selection

I have a simple issue. I have a filedialog in a wpf application. Things works fine when I run the application for the first time. But when I change the file extension, and change back, I dont see anything.
This is the code:
Filedlg.FileName = "*.msr"; // Default file name
Filedlg.DefaultExt = ".msr"; // Default file extension
Filedlg.Filter = "Raw (.msr)| *.msr | All files |*.*" ; // Filter files by extension
I see .msr files. Then I choose to see all files and then switch back to .msr extension. But I dont see any files.
Thoughts?
Kindly ask details if required.
If you are using Filter property, DefaultExt gets ignored or in worst case can cause issues. You need to use FilterIndex instead to mark default extension. You can find out more here.
I would also skip setting file name to *.msr.
try this:
Filedlg.Filter = "Raw (.msr)| *.msr |" + "All Files(*.*)|*.*";
Filedlg.Filter = "Raw (.msr)|.msr|All Files(.)|.";
this one works. Problem was extra space between | All.

How to restrict filename modification in OpenFileDialog in C#

I have a C# .NET 3.5 program that uses an OpenFileDialog to retrieve a file for importing. It has two filters (*Domain*.* and *.*) and the *Domain*.* is chosen as the FilterIndex. I'm seeing a case of a disappearing file from the filters when it is modified within the OpenFileDialog.
Here are the steps the user will take to reproduce the problem:
In the program, open the OpenFileDialog. Ensure that the filter is set to *Domain*.*.
Find a file in the directory that matches the filter and change the file name so that it no longer matches the filter. Note: the file will disappear.
Change the filter to show all files *.*. Note: the file is not listed even though you're supposedly showing *.*.
At this point, you can open the folder in Windows Explorer and see that the file with the changed name exists. However, in the OpenFileDialog, it is no longer visible regardless of the filter that is used. The only way to see that file again is to close the OpenFileDialog and then reopen it.
Here is my code that creates the OpenFileDialog.
using(OpenFileDialog domainFileDialog = new OpenFileDialog())
{
domainFileDialog.CheckFileExists = true;
domainFileDialog.CheckPathExists = true;
domainFileDialog.Filter = "Domain Files (*Domain*.*)|*Domain*.*|All files (*.*)|*.*";
domainFileDialog.FilterIndex = 1;
domainFileDialog.Multiselect = false;
domainFileDialog.RestoreDirectory = true;
domainFileDialog.ShowReadOnly = true;
domainFileDialog.SupportMultiDottedExtensions = true;
domainFileDialog.Title = "Choose the Domain File to Import...";
domainFileDialog.ValidateNames = true;
\\ Perform Import functionality...
}
It seems as though when you open the OpenFileDialog and modify an existing file that matches the more restrictive filter so that it no longer matches the filter, the file disappears from visibility even when all files *.* are displayed.
Since I have no idea why this is happening, (and I'm open for suggestions as to how to fix it) is there any way to restrict a user from creating or modifying any of the files in the OpenFileDialog in hopes of preventing this problem?
First, I'd suggest you consider whether it is worth caring that the user might do this. If the FOD does this, every windows application has this feature, but you don't hear users complaining about it. So is it really an issue that needs fixing?
It wouldn't surprise me if the problem's related to the filter being for more than just a file extension - it's rather unconventional to do this. Maybe try it with an extension only and see if this is the cause.
Have you tried pressing F5 to refresh its cached data? I don't know if this would work in a FOD as it does in an explorer window, but it might be interesting to give it a try.
Having said all that, it would be trivial to filter keypresses (F2) and mouse clicks (right button) )(with some forms you could derive off it, or you could drop in a MessageFilter) to make it impossible for a user to access any UI that allows them to rename a file in the FOD. It would piss me off, as a user, if you broke the FOD in this waym though - much more than a renamed file "disappearing" under rare circumstances, anyway.
http://msdn.microsoft.com/en-us/library/microsoft.win32.openfiledialog.aspx
The OpenFileDialog doesn't itself support any such functionality. I think your best bet at this point is writing your own open-file dialog window. You would gain a great deal of control that way and it wouldn't take too long.

OpenFileDialog - only display filenames that have no extensions

I have the following code in my C# program:
OpenFileDialog fDialog = new OpenFileDialog();
fDialog.Title = "Open a file";
fDialog.Filter =
"NCF files (*.ncf)|*.ncf|All files (*.*)|*.*|No Extensions (*.)|*.";
I want to be able to have the user pick from the following:
*.NCF (files with .NCF extension only)
**.* (all files)
and files that have no extensions such as:
filewithnoextension
I know ***.* will do this, but it also displays the .NCF, .TXT, and all other files in the same directory. I just want to be able to display filenames that have no extensions.
Filtering with *. does not do the trick. It works fine when doing it with a DOS window (dir *.) , but C# seems to ignore the *. filter.
Is there a way I can do this with C#?
Thanks.
I know this works:
fDialog.Filter = "No extension Files|" + null;
I haven't tested with multiple selections..
Altough this is an old post, I though it would benefit someone looking for a way to only display files with no extensions..
A readme file normally has an extension. I suppose you did, but did you check this folder option to see the extensions of known file types? Has it changed anything?
EDIT #1
Frankly, I doubt you'd be able to make the OpenFileDialog display files with no extension, as the Filter property is based on the extension.
Perhaps you could inherit base your own implemented OpenFileDialog using the System.IO namespace objects such as DirectoryInfo, for instance, which will allow you to get the browsed folder files with the Getfiles() method, then filter yourself through LINQ to display the files with no extension only with the FileInfo.Extension property.
EDIT #2
Since the OpenFileDialog is sealed, you may use it as a nested type and implement your own methods using this nested type.
I hope this helps you!
If the other software program creates these files in the same location, why not have your code add an extension (something innocuous like ".XXX") to every extension-less file in that folder, and then show the dialog?
Edit: Or, see this MSDN article:
http://msdn.microsoft.com/en-us/library/ms646960(VS.85).aspx
From the Filters section:
The CDN_INCLUDEITEM notification
message provides another way to filter
the names that the dialog box
displays. To use this message, provide
an OFNHookProc hook procedure and
specify the OFN_ENABLEINCLUDENOTIFY
flag in the OPENFILENAME structure
when you create the dialog box. Each
time the user opens a folder, the
dialog box sends a CDN_INCLUDEITEM
notification to your hook procedure
for each item in the newly opened
folder. The return value of the hook
procedure indicates whether the dialog
box should display the item in the
folder's item list.
Down at the bottom in the Explorer-Style Hook Procedures section, the article explains how to do this. Basically, you pass an event handler to the OpenFile dialog, and each time the user navigates to a new folder, the dialog iterates through all the files in the folder and calls your event handler for each one. Inside the event handler, you would put your code to determine if the file has an extension or not, and return true or false, accordingly.
I thought using *. would work, but it doesn't, so it seems that's a limitation of the OpenFileDialog control.
You could create your own dialog but the OpenFileDialog is not inheritable so this would end up being a lot of work for just a small feature.
Is the file with no extension created by your own application? If that's the case, you could give it a custom extension for your filtering. If it's not, then I'm afraid I can't think of anything else to help you :(
Good luck!

Categories

Resources