I want to display progress of saving a file using the "SaveFileDialog" and "Progress Bar" in a windows form. The file being saved is text file (rtf, txt, ...). This is what I use to save a file:
private void Save()
{
if (TabControl.TabPages.Count != 0)
{
SaveFileDialog.FileName = TabControl.SelectedTab.Name;
SaveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); //default path
SaveFileDialog.Filter = "Rich Text Format|*.rtf";//Extensions
SaveFileDialog.Title = "Save";
if (SaveFileDialog.ShowDialog() == DialogResult.OK)
{
if (SaveFileDialog.FileName.Length > 0)
{
GetCurrentDocument.SaveFile(SaveFileDialog.FileName, RichTextBoxStreamType.RichText);//Stream Type for .rtf
}
}
else if (SaveFileDialog.ShowDialog() == DialogResult.Cancel)
{
StatusBar.Text = "Saving Cancelled."; //Makes sure it doesn't crash on cancel
}
}
else
{
StatusBar.Text = "Can't save. No tabs are detected.";
}
}
The GetCurrentDocument is this:
private RichTextBox GetCurrentDocument
{
get
{
return
(RichTextBox)TabControl.SelectedTab.Controls["Body"];
}
}
Thus, SaveFile() is:
RichTextBox.SaveFile Method: Saves the contents of the RichTextBox to a file.
msdn page
Somehow I want to display the saving on the progress bar, or at least display a notice when the saving is finished (when the file is in the final location).
You will need a progress bar as a Marquee style as you don't know how long it will take to save the file.
Try this
what kinf of class is getcurrentdocument and what savefile method do.
Could You use BackgroundWorker for save the file and open an progress bar in the ui waiting for a signal of the end of the workprocess.
Howto
Write me if this solution it isn't enought.
Related
NB: The answer in this question is out of date.
So, I have a save dialog box:
...
SaveFileDialog sfd = new SaveFileDialog();
sfd.ShowDialog();
// SaveFileDialog.[Whatever] - Init code basically.
if (sfd.DialogResult == DialogResult.OK)
{
// Definitely do something.
Console.Print("File selected.");
}
if (sfd.DialogResult == DialogResult.Abort)
{
// Maybe the opposite of the above?
Console.Print("File selection Cancelled");
}
if ( ... ) { }
and so on.
But... SaveFileDialog.DialogResult has been replaced by events instead...
And that the only available events are SaveFileDialog.FileOK, SaveFileDialog.Disposed and SaveFileDialog.HelpRequest.
How do I trigger an event (or move to a line of code) based when the user clicked Cancel rather than completing it (Clicking Save)?
I'm looking to branch based on whether the user cancels or successfully selects the file location to save to.
Working with DialogResult is not deprecated and also those events are not something new.
To perform an action for Cancel, you can create your SaveFileDialog and configure it, you can call ShowDialog and then check the result:
var sfd= new SaveFileDialog();
//Other initializations ...
//sfd.Filter= "Text files (*.txt)|*.txt|All files (*.*)|*.*";
//sfd.DefaultExt = "txt";
if(sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
MessageBox.Show("Save Clicked");
//ِDo something for save
}
else
{
MessageBox.Show("Cancel Clicked");
//Do something for cancel
}
You can access to selected file using FileName property, for example MessageBox.Show(sfd.FileName);
I created simple program for save/open practice. Made a setup and associated my program with my own datatype, called it .xxx (for practice).
I managed to Save and Open code and data from textbox but only from my program. Double click (or enter from windows-desktop) open up my WindowsForm as it is but there is an empty textbox. I want my saved file to be opened on double click in the same condition as when I open it from my program. How to set that up??
Here is the code of simple app (cant post images but it simple - got 1 label and 1 textbox with open and save buttons):
private void ButOpen_Click(object sender, EventArgs e)
{
textBox1.Text = "";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
string data = Read(openFileDialog1.FileName);
textBox1.Text = data;
}
else
{//do nothing }
}
private string Read(string file)
{
StreamReader reader = new StreamReader(file);
string data = reader.ReadToEnd();
reader.Close();
return data;
}
private void ButSave_Click(object sender, EventArgs e)
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "Something|*.xxx";
DialogResult result = saveFileDialog1.ShowDialog();
string file = saveFileDialog1.FileName.ToString();
string data = textBox1.Text;
Save(file, data);
}
private void Save(string file, string data)
{
StreamWriter writer = new StreamWriter(file);
writer.Write(data);
writer.Close();
}
NOTE:
My similar question was marked as duplicate but it is not, and this question which was referenced as duplicate Opening a text file is passed as a command line parameter does not help me.It's not the same thing...
Just wanted to find out how to configure registry so windows understand and load data inside the file, or to file save data somehow so i can open it with double click.
So someone please help. If something is not clear I will give detailed information just ask on what point.
Thanks
MSDN has some information about this:
https://msdn.microsoft.com/en-us/library/bb166549.aspx
Basically you need to create an entry in the registry so that explorer.exe knows to launch your program when that file is activated (e.g. double-clicked).
Explorer will then pass the path to the file as an argument to your program.
I'm still a beginner when it comes to programming and this is a small application I did following a C# tutorial.
private void viewImagesToolStripMenuItem_Click(object sender, EventArgs e)
{
string openedfile = "";
openfd.Title = "Insert a text file";
openfd.InitialDirectory = "C:";
openfd.FileName = "";
openfd.Filter = "text files|*.txt|word documents|*.doc|allfiles|*.*";
if (openfd.ShowDialog() == DialogResult.Cancel)
{
MessageBox.Show("Operation canceled");
}
if (openfd.ShowDialog() != DialogResult.Cancel)
{
openedfile = openfd.FileName;
richTextBox1.LoadFile(openedfile,RichTextBoxStreamType.PlainText);
}
While doing this I noticed that if I change the same application's code order just 2 lines-
string openedfile = "";
openedfile = openfd.FileName;
like below It will throw me an error like this when debugging - Empty path name is not legal.
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
openfd.Title = "Insert a text file";
openfd.InitialDirectory = "C:";
openfd.FileName = "";
openfd.Filter = "text files|*.txt|word documents|*.doc|allfiles|*.*";
**string openedfile = "";
openedfile = openfd.FileName;**
if (openfd.ShowDialog() == DialogResult.Cancel)
{
MessageBox.Show("Operation canceled");
}
if (openfd.ShowDialog() != DialogResult.Cancel)
{
richTextBox1.LoadFile(openedfile,RichTextBoxStreamType.PlainText);
}
Isn't there a way to understand errors in these type situations. What is the specific order of coding an application like this?
well, the idea is simple you cannot use a variable that has been not initialized.
in your case sm thing same is happening.
In your first code openedfile = openfd.FileName; is being executed after the dialouge has been shown. Thus the file name comes correctly.
But in the second openedfile = openfd.FileName; is getting initialized before the dilogue has been shown. Since there is no dialogue the name is null, hence it gives error.
Note. I have used initialized word not in tecnical manner.
The line openedfile = openfd.FileName; will not bind the two variables, it will copy the value that openfd.FileName has at this moment into openedfile.
In your second example the user has not yet selected a file at that moment, so this value is still empty (""). The value that is selected later in openfd will be ignored.
EDIT which is why you get the error Empty path name is not legal.
I'm going to go ahead and guess that the problem is the openfd.FileName call outside of the if block (and also before its retrieved), while the if block is still being exectuted the openfd is "left open" if you like, so you can retrieve its result.
When you have left, the if block, you are effectively saying you are done with this dialog, please continue.
In your code you are showing multiple dialogs with multiple calls to show dialog also, consider the following.
if (openfd.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = Image.FromFile(openfd.FileName);
}
else
{
MessageBox.Show("Operation canceled");
}
(Changed to use dialogresult.ok as this is more than likely the result you wish to receive from the dialog)
Update
With respect to your current applcation, each call to ShowDialog() is opening a new dialog. Consider it similar to
MessageBox.Show("woo");
MessageBox.Show("hoo");
in the above, when the first messagebox is closed, it will close the dialog and move onto handling the second message box (the next line of code), with your
if (openfd.ShowDialog() != DialogResult.Cancel)
Your showdialog is still in use by the if statement so it is deemed to be still in use and not disposed of straight away. When the if statement is finished with, your dialog will then be deemed to be ok to dispose
Also, the error in your application is not to do with the filename path, its trying to load in a file that has no name
I generally Prefer this:
private void viewImagesToolStripMenuItem_Click(object sender, EventArgs e)
{
DialogResult dr=openfd.ShowDialog();
if(dr==DialogResult.Ok)
{
richTextBox1.LoadFile(openfd.FileName,RichTextBoxStreamType.PlainText);
}
else
{
MessageBox.Show("No file Selected!!");
}
}
I am trying to make SaveFileDialog and FileOpenDialog enforce an extension to the file name entered by the user. I've tried using the sample proposed in question 389070 but it does not work as intended:
var dialog = new SaveFileDialog())
dialog.AddExtension = true;
dialog.DefaultExt = "foo";
dialog.Filter = "Foo Document (*.foo)|*.foo";
if (dialog.ShowDialog() == DialogResult.OK)
{
...
}
If the user types the text test in a folder where a file test.xml happens to exist, the dialog will suggest the name test.xml (whereas I really only want to see *.foo in the list). Worse: if the user selects test.xml, then I will indeed get test.xml as the output file name.
How can I make sure that SaveFileDialog really only allows the user to select a *.foo file? Or at least, that it replaces/adds the extension when the user clicks Save?
The suggested solutions (implement the FileOk event handler) only do part of the job, as I really would like to disable the Save button if the file name has the wrong extension.
In order to stay in the dialog and update the file name displayed in the text box in the FileOk handler, to reflect the new file name with the right extension, see the following related question.
You can handle the FileOk event, and cancel it if it's not the correct extension
private saveFileDialog_FileOk(object sender, CancelEventArgs e)
{
if (!saveFileDialog.FileName.EndsWith(".foo"))
{
MessageBox.Show("Please select a filename with the '.foo' extension");
e.Cancel = true;
}
}
AFAIK there's no reliable way to enforce a given file extension. It is a good practice anyway to verify the correct extension, once the dialog is closed and inform the user that he selected an invalid file if the extension doesn't match.
The nearest I've got to this is by using the FileOk event. For example:
dialog.FileOk += openFileDialog1_FileOk;
private void openFileDialog1_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
{
if(!dialog.FileName.EndsWith(".foo"))
{
e.Cancel = true;
}
}
Checkout FileOK Event on MSDN.
I ran into this same issue, and I was able to control what was shown by doing the following:
with the OpenFileDialog, the first item in the filter string was the default
openFileDialog1.Filter = "Program x Files (*.pxf)|*.pxf|txt files (*.txt)|*.txt";
openFileDialog1.ShowDialog();
with the SaveFileDialog, the second item in the filter was used as the default:
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "txt files (*.txt)|*.txt|Program x Files (*.pxf)|*.pxf";
saveFileDialog1.FilterIndex = 2;
saveFileDialog1.RestoreDirectory = true;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
if (saveFileDialog1.FileName != null)
{
// User has typed in a filename and did not click cancel
saveFile = saveFileDialog1.FileName;
MessageBox.Show(saveFile);
saveCurrentState();
}
}
After having used these two filters with the respective fileDialogs, The expected results finally occurred. By default, when the user selects the save button and the savefiledialog shows up, the selected filetype is that of the Program X files type defined in the filter for the savefiledialog. Likewise the selected filetype for the openfiledialog is that of the Program X Files Type defined in the filter for the openfileDialog.
It would also be good to do some input validation as mentioned above in this thread. I just wanted to point out that the filters seem to be different between the two dialogs even though they both inherit the filedialog class.
//this must be ran as administrator due to the change of a registry key, but it does work...
private void doWork()
{
const string lm = "HKEY_LOCAL_MACHINE";
const string subkey = "\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete";
const string keyName = lm + subkey;
int result = (int)Microsoft.Win32.Registry.GetValue(keyName, "AutoComplete In File Dialog", -1);
MessageBox.Show(result.ToString());
if(result.ToString() == "-1")
{
//-1 means the key does not exist which means we must create one...
Microsoft.Win32.Registry.SetValue(keyName, "AutoComplete In File Dialog", 0);
OpenFileDialog ofd1 = new OpenFileDialog();
ofd1.ShowDialog();
}
if (result == 0)
{
//The Registry value is already Created and set to '0' and we dont need to do anything
}
}
i want to use a background thread for the process of loading the XML data, possibly with a progress bar to let the user know that the application is actively doing something.
i have written this code through searching the net.
i want to load a XML tree in treeview on winform when a user cliks a Browse button.
In case of a large XML file the winform freezes.So to let the user know that in background the work is going on i want to add a progress bar.i have used a background worker here.
But it is raising an exception of System.ArgumentException showing this message "The URL cannot be empty.\r\nParameter name: url" on xmlDocument.Load(txtFileName.Text); this line.
My xml file is in correct format and is at the proper location where i selected.
But i am unable to find the cause of this exception.
Can you please help out or tell me the correction in my code?
Thanks....
private void btnBrowse_Click(object sender,EventArgs e)
{
bgWorker1.RunWorkerAsync();
StripProgressBar.Value = 0;
toolStripStatusLabel1.Text = "Browsing for a Xml file";
if (open.ShowDialog(this) == DialogResult.OK)
{
txtFileName.Text = open.FileName;
initiatingTree(open.FileName); //this variable gives the name of selected file
}
while (this.bgWorker1.IsBusy)
{
StripProgressBar.Increment(1);
// Keep UI messages moving, so the form remains
// responsive during the asynchronous operation.
Application.DoEvents();
}
}//Browse button
private void bgWorker1_DoWork(object sender, DoWorkEventArgs e)
{
xmlDocument = new XmlDocument();
Thread.Sleep(5000);
xmlDocument.Load(txtFileName.Text);
btnBrowse.Enabled = false;
}
private void bgworker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Set progress bar to 100% in case it's not already there.
StripProgressBar.Value = 100;
if (e.Error == null)
{
MessageBox.Show(xmlDocument.InnerXml, "Download Complete");
}
else
{
MessageBox.Show("Failed to download file");
}
// Enable the Browse button and reset the progress bar.
this.btnBrowse.Enabled = true;
StripProgressBar.Value = 0;
toolStripStatusLabel1.Text = "work finished processing request.";
}//workerCompleted
You're starting the asynchronous process immediately when the user clicks "Browse", by calling
bgWorker1.RunWorkerAsync();
This calls the DoWork method of your background worker, which sleeps for 5 seconds, and pulls the value from txtFileName.Text whether or not the user has completed their entry in the FileOpenDialog.
You'd be better off moving the byWorker1.RunWorkerAsync() (and the busy waiting) into the if (open.ShowDialog(this) == DialogResult.OK) block.
private void btnBrowse_Click(object sender,EventArgs e)
{
StripProgressBar.Value = 0;
toolStripStatusLabel1.Text = "Browsing for a Xml file";
if (open.ShowDialog(this) == DialogResult.OK)
{
txtFileName.Text = open.FileName;
initiatingTree(open.FileName);
bgWorker1.RunWorkerAsync();
while (this.bgWorker1.IsBusy)
{
StripProgressBar.Increment(1);
// Keep UI messages moving, so the form remains
// responsive during the asynchronous operation.
Application.DoEvents();
}
}
}
For these kinds of problems, it can be helpful to put a breakpoint right where the file is going to get loaded, and see what the value is when that happens... you might notice that it's getting called with an empty string.
You might also consider the version of RunWorkerAsync that takes a parameter; you could pass the file in that way, instead of trying to read it asynchronously from the textbox.
And personally, I wouldn't use a loop that calls Application.DoEvents(); instead I'd return control back to the UI thread and then Invoke() onto it from the asynchronous thread to effect the progressbar updates.
When the method bgWorker1.RunWorkerAsync(); is called the event DoWork is fired.
Because the method is called in the beginning of the application, the file name text box is empty.
I hope you've understood.