I have an OpenFileDialog and I only want to allow .txt as a valid file for the users.
I know I can add a Filter to the OpenFileDialog like so:
var dialog = new OpenFileDialog();
dialog.DefaultExt = ".txt";
dialog.Filter = "Text Files (*.txt)|*.txt";
var result = dialog.ShowDialog();
// Do something with the result
The problem however, is that I can still directly say something like "test.jpg" in the OpenFileDialog and then it opens this uploads this .jpg file. (Obviously it goes wrong somewhere later, but that doesn't matter for now.) I just want to know how I can restrict the user to only add ".txt" files, nothing else? (By directly validation it inside the OpenFileDialog, instead of doing it somewhere later.)
You cant do that only in OpenFileDialog and even if you could its a bad limitation.
Using the *.txt example there are multiple files extensions that are plain text inside, *.bat or all the codding file extensions *.cs, *.js, etc...
You should not limit the user on what file he can put on it.
For more complex file types if your program cant handle the file passed by the user you should show an error not prevent the user from passing the file.
Related
I have an application which currently provides the user with the ability to view a PDF file inside the application by using File->Open, browsing to the location of the PDF file using a Microsoft.Win32.OpenFileDialog, and then displaying that PDF file in a System.Windows.Controls.WebBrowser in the GUI.
I am creating the OpenFileDialog and setting the file extensions it can open using:
/*Create Open File dialog */
Microsoft.Win32.OpenFileDialog OFDlg = new Microsoft.Win32.OpenFileDialog();
/*Set filter for file extension and default file extension */
OFDlg.DefaultExt = ".pdf";
OFDlg.Filter = "PDF Documents (.pdf)|*.pdf";
I now want to extend this, so that the user can open a ZIP folder containing a single PDF document, and display that PDF document in the same way that I am above.
I tried changing the filter to allow .zip files, i.e.
OFDlg.DefaultExt = ".pdf|.zip";
OFDlg.Filter = "PDF Documents (.pdf)|*.pdf|ZIP|*.zip";
but when I browse to the location of the .zip file in the OpenFileDialog, the .zip folder is not displayed there- only normal folders and PDF documents (other documents in that directory, such as .doc & .xls are not displayed in the OpenFileDialog).
My reason for wanting to be able to open the contents of a .zip file directly from the .zip, rather than navigating to that file itself, is so that I can add public/private key encryption to the .zip, so that its contents can only be read securely.
I know that there could in theory be problems if the .zip contains more than one file, but I intend to send each encrypted file in its own zip folder, so it can be assumed that any zip file that the user is trying to open contains a single .pdf, and nothing else.
So my questions are:
How can I make .zip folders visible from the OpenFileDialog?
How can I make the selection of that .zip folder automatically open and display its contents (a single PDF file) in the System.Window.Controls.WebBrowser that I am currently using to display PDFs in my GUI?
Edit 1
I tried changing my OpenFile() method to the following code:
/*Set filter for file extension and default file extension */
OFDlg.DefaultExt = ".pdf";
OFDlg.DefaultExt = ".zip";
OFDlg.Filter = "PDF Documents (.pdf)|*.pdf";
OFDlg.Filter = "ZIP Folders (.ZIP)|*.zip";
but when I now run my application, and browse to the same location, although the .zip folder is now shown in the OpenFileDialog, the .pdf files no longer are... and if I double click the .zip folder, my application breaks, and I get a runtime error on the line
PdfPanel.OpenFile(docFP);
which says:
An unhandled exception of type 'System.AccessViolationException' occurred in MoonPdfLib.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I guess that's to do with the MoonPDF library that I'm using to read the PDFs being unable to handle the .zip extension?
How would I resolve this to be able to open the PDF inside the ZIP?
Edit 2
Ok, so I've resolved the issue about only being able to see either the PDF files or the .ZIP folders (not both at the same time), by moving the functionality into two separate methods- one to display the PDF direct from the PDF's filepath, and another to display the PDF from the path of the .ZIP folder holding it.
The method for displaying the PDFs directly currently works (it is essentially the code in the first bit of code I've quoted). However the method for displaying the PDFs from the ZIP currently doesn't work...
I understand the reason for this- it's because I am passing a .zip folder to the OpenFile method... The code for this method currently looks like this:
private void openZipMenuItem_click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog OZipDlg = new Microsoft.Win32.OpenFileDialog();
OZipDlg.DefaultExt = ".zip";
OZipDlg.Filter = "ZIP Folder (.zip)|*.zip";
Nullable<bool> result = OZipDlg.ShowDialog();
if (result == true)
{
/*Open document */
string filename = OZipDlg.FileName;
//fnTextBox.Text = filename;
zipFP = OZipDlg.FileName;
/*browser.Navigate(docFP); ERF (27/05/2016 # 0935) Comment this line- I want to use PdfPanel to open docFP, not browser */
Console.WriteLine("Panel height: " + PdfPanel.ActualHeight);
PdfPanel.OpenFile(zipFP);
}
}
When I try to call this function to open a .zip, I get a runtime exception which says:
AccessViolationException was unhandled
An unhandled exception of type 'System.AccessViolationException' occurred in MoonPdfLib.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I understand that I can't display a Zip folder in the PdfPanel (which is a MoonPdfPanel that I am using from the MoonPdfLibrary), so I know that I will get an exception here.
How can I pass the contents of zipFP to the call to PdfPanel.OpenFile(), rather than passing zipFP itself to it?
Edit 3
Ok, so my code is currently extracting the PDF file successfully from the ZIP folder when I open it- I can see that it is copied to the directory I have specified. I am now trying to get the PDF to be displayed automatically in the PDF Panel on my application- I've done this by adding the following code:
try{
string extractPath = #"C:\Documents";
using(ZipArchivev zip = ZipFile.Open(zipFP, ZipArchiveMode.Read))
foreach(ZipArchiveEntry entry in zip.Entries){
try{
ZipFile.ExtractToDirectory(zipFP, extractPath);
Console.WriteLine("zipFP: " + zipFP);
}catch(System.IOException){
Console.WriteLine("File already exists...");
}
}
string ExtractedPDF = string.Concat(extractPath, zipFP);
PdfPanel.OpenFile(ExtractedPDF);
}catch(AccessViolationException ex){
Console.WriteLine("Can't display a zip in the PDF panel..." + ex.InnerException);
}
But when my code tries to execute the line PdfPanel.OpenFile(ExtracedPDF);, I get an exception that says:
FileNotFoundException was unhandled | An unhandled exception of type 'System.IO.FileNotFoundException' occurred in MoonPdfLib.dll'
I understand that this is happening because the variable I am trying to display in the PDFPanel, ExtractedPDF actually holds the path of the folder containing the PDF, and not the PDF itself- How do I give it the name of the PDF file, when I don't actually know what the PDF file will be called?
Here is something works similar to your requests, the logic behind the code is:
Only display zip and pdf files in the OpenFileDialog
If user selected a pdf file, show it in the panel
If user selected a zip file, change the directory of the OpenFileDialog to the zip file(treat it like a folder)
Example code (working code....):
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "PDF files (.pdf)|*.pdf;*.zip";
ofd.ShowDialog();
//reopen OpenFileDialog if it is zip file. this part can be improved.
if (ofd.FileName.EndsWith(".zip"))
{
ofd.InitialDirectory = ofd.FileName;
ofd.ShowDialog();
}
//if it's a PDF, note that you don't really need this check,
//as the only file can reache here will be a PDF,
//and it can be the temporary file that inside a zip.
if(ofd.FileName.EndsWith(".pdf"))
{
//show it in your PdfPanel
}
Edit, based on your new comments and added code. you need to change your code to the following as your current code is mistaken directory with the file:
try{
string extractPath = #"C:\Documents";
string ExtractedPDF ="";
using(ZipArchivev zip = ZipFile.Open(zipFP, ZipArchiveMode.Read))
foreach(ZipArchiveEntry entry in zip.Entries){
try{
ExtractedPDF= Path.Combine(extractPath, entry.FullName);
entry.ExtractToFile(ExtractedPDF,true);
}catch(System.IOException){
Console.WriteLine("error during extraction...");
}
}
if( System.IO.File.Exists(ExtractedPDF))
{
PdfPanel.OpenFile(ExtractedPDF);
}
}catch(AccessViolationException ex){
Console.WriteLine("Can't display a zip in the PDF panel..." + ex.InnerException);
}
If you want to support multiple file formats in an open file dialog, you need to add a third (or better first) option, that aggregates all supported file extensions:
OFDlg.Filter = "Supported file formats|*.pdf;*.zip|PDF Documents|*.pdf|ZIP files|*.zip";
First, regarding showing the files in the open file dialog. Your initial method for doing this was correct. Your updated code now first sets the filter to show PDFs, then replaces that filter with one that shows zip files. The standard file open dialog isn't designed to show different file types at the same time. The right way to handle that is to give the user the option for which file types they want to show.
Typically, an "All files" option is added as well (with . as the search pattern). This way if the file type the user wants to open isn't available in the list, they can see it regardless.
As for opening the PDF file that is in the zip file, you need to take are of extracting the PDF file yourself. This question has some options for how to do that.
I have a problem where if you set the filename in the dialog box to a sub directory within the initial directory you set it to and then clicking 'Save', the dialog window doesn't actually save the file but opens the sub directory which I could still interact with.
For example If I set the initial directory for the dialog to 'C:\MainDir' and that directory consists of SubDir1, SubDir2, then in the save file dialog I could see that I am in the initial directory with two sub directories. If I set the filename to SubDir1 (no extension) in the dialog, and then I hit 'Save', what happens is instead of saving the file as 'filename.extension' the dialog opens the directory specified by the file name.
Here's what I currently have:
SaveFileDialog dlg = new SaveFileDialog();
dlg.DefaultExt = ext;
dlg.AddExtension = true;
dlg.FileName = filename;
dlg.Filter = filter;
dlg.FileOk += OnFileDialogOk;
dlg.InitialDirectory = dir;
bool? dlgRes = dlg.ShowDialog();
Is this something that can be easily fixed?
Quick Answer: No.
You cannot override the default save method of Windows OS.
What you can do is perhaps to verify whether the filename you wanted to use (in this instance, SubDir) exists already as a directory. If it does, then you would need to change that name, as that will only manifest the behavior you've already seen.
Side Note: Just imagine you have a very important folder which contains critical files, and Windows would let you save a file that is named with that directory. That is a disaster waiting to happen.
The only ways I can think of doing this are a bit extreme:
You could roll your own dialog
You could modify the functionality of the standard dialog
The answers found here: Customizing OpenFileDialog could help with that.
I guess I should also note that while it may seem helpful to accommodate this kind of input and automatically append the extension, it'll be counter-intuitive to many users who will expect the default behaviour.
In short, I'd probably think twice about this.
I'm using OpenFileDialog (.Net Framework 4, Windows 10) and I've noticed that it will allow the user to specify a URL as the file name (e.g., http://somewebsite/picture.jpg). This is very useful for my application, so I don't intend to disable it. The way it works is downloading the file into the user's temp directory and returning the temporary file name in the dialog's Filename property. This is nice, except for the fact that the user starts to build up garbage in his/her temp directory.
I would like to tell when a file was downloaded by the OpenFileDialog class (as opposed to a previously existing file), so I can clean up by deleting the file after use. I could check if the file's directory is the temp directory, but that's not very good since the user might have downloaded the file him/herself.
I've tried intercepting the FileOK event and inspect the Filename property to see if it is an HTTP/FTP URI, but despite what the documentation says ("Occurs when the user selects a file name by either clicking the Open button of the OpenFileDialog") it is fired after the file is downloaded, so I don't get access to the URL: the Filename property already has the temporary file name.
EDIT: This is an example of what I'like to do:
Dim dlgOpenFile As New System.Windows.Forms.OpenFileDialog
If dlgOpenFile.ShowDialog(Me) <> Windows.Forms.DialogResult.OK Then Return
''//do some stuff with dlgOpenFile.Filename
If dlgOpenFile.WasAWebResource Then
Dim finfo = New IO.FileInfo(dlgOpenFile.Filename)
finfo.Delete()
End If
In this example, I've imagined a property to dlgOpenFile "WasAWebResource" that would tell me if the file was downloaded or originally local. If it's the first case, I'll delete it.
There's no obvious way to do this, but as a workaround, how about checking where the file lives? It looks like by default this dialog downloads files to the users Temporary Internet Files directory, so you could introduce some code that looks something like this:
FileDialog dialog = new OpenFileDialog();
if (dialog.ShowDialog() == DialogResult.OK)
{
string temporaryInternetFilesDir = Environment.GetFolderPath(System.Environment.SpecialFolder.InternetCache);
if (!string.IsNullOrEmpty(temporaryInternetFilesDir) &&
dialog.FileName.StartsWith(temporaryInternetFilesDir, StringComparison.InvariantCultureIgnoreCase))
{
// the file is in the Temporary Internet Files directory, very good chance it has been downloaded...
}
}
I'm learning C and C#, this question is for C#. I have a app that I want to open files on my C:\ drive. Can I use OpenFileDialog to open any type of file? How is this done?
Here is the code:
case 1:
openSomething();
break;
private static void openSomething()
{
OpenFileDialog open = new OpenFileDialog();
open.Filter = "All Files (*.*)|*.*";
open.ShowDialog();
if (open.ShowDialog() == DialogResult.OK)
{
File.Open(open.FileName); // I want to do something like this
}
}
Is there something like System.Diagnostics.Process.Start on programs for files, so I use openfiledialog to get the filename and then my code opens the file with the default application?
Edit: I answered my own question
private static void openSomething()
{
OpenFileDialog open = new OpenFileDialog();
open.Filter = "All Files (*.*)|*.*";
if (open.ShowDialog() == DialogResult.OK)
{
System.Diagnostics.Process.Start(open.FileName);
}
}
Usually the program tries to limit the kind of files listed by OpenFileDialog using the Filter property, but, if you want to allow the opening of any kind of file you set this property (before calling ShowDialog) with something like this
open.Filter = "All Files (*.*)|*.*";
meaning that every kind of file could be choosen by your user.
Keep in mind that the Filter property is just a facility to give a rapid choice to the end user, by itself the OpenFileDialog can open any kind of files also if you set any specialized filter.
All that your user is required to do is typing the *.* in the filename textbox space and he/she can choose any kind of file (of course only if he/she has the required file/folder access permissions)
After the ShowDialog returns DialogResult.OK you could check if there is something selected in the Filename property, and, if you want to open the file using the default application associated for the file extension then you use Process.Start
if (open.ShowDialog() == DialogResult.OK)
{
if(open.FileName.Trim() != string.Empty)
{
Process.Start(open.FileName);
}
}
Of course this could be problematic if the file choosen has no default program associated (for example what if the user choose a DLL?), so perhaps it is better to apply a filter to select only a subset of well known file types. But this depends on your requirements.
The OpenFileDialog really only serves as a window to let the user select a file or multiple files. It does not open any file. The selected filenames can be retrieved from the FileName or FileNames properties after dialog has been closed. To open and read / edit the file is an independent task.
According to this msdn article one of the sources for InitialDirectory property used in FileDialog is:
A path that was previously used in the program, perhaps retained from the last directory or file operation.
...
So if you selected your first file from folder x, the next time you try to select a file it will open up the FileDialog with with folder x selected (saving you having to navigate there).
Playing around with notepad this seems to carry across opening a file, saving a file, opening a file and even when printing with "Microsoft XPS Document Writer" which brings up it's own dialog.
So my question is where is this value stored between dialogs? I would like to be able to see what it is and potentially change it? The specific area i would like to change it is in the "Microsoft XPS Document Writer" printer which brings up it's own dialog. So it's not as simple as just setting the initalDirectory Value.
It's stored in the registry, somewhere in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\ (LastVisitedPidlMRU).
You should take a look at this link:
MRU locations are what you are looking at!
Here's a way for accessing it:
var openFileDialog1 = new OpenFileDialog();
string path = openFileDialog1.InitialDirectory;
// you can change path if you want
openFileDialog1.InitialDirectory = path;
// after you are donw you can display you dialog
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
// do something
}
Another way is to use Directory.SetCurrentDirectory method which sets the application's current working directory
And from Microsoft website, it is stored at this location in the registry:
//The MRU lists for Windows Explorer-style dialog boxes are stored by file type for each user in the following registry key:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSaveMRU
hope this helps