I writing code to upload pdf file onto the third party server. I have done some path validation checks. I am checking if the file exists or not. Now for this validation the c# automatically throws an exception message box, without closing file dialog(browser window). I want to implement same validation for file extension. I tried checking for extension and then throwing the exception in message box, but the file dialog closes. I am attaching a screen shot so that this becomes clearer.
This type of validation I want and the background window should remain open
This validation I want to implement for file extension. As far as I know there are not exceptions for validating file extensions.
public System.Windows.Forms.OpenFileDialog cmndBrowseOpen;
public System.Windows.Forms.SaveFileDialog cmndBrowseSave;
public System.Windows.Forms.DialogResult cmdBrowseResult
public void cmdBrowse_Click()
{
const string sFilter = "PDFs (*.pdf)|*.pdf";
string sMsg = String.Empty;
string sTitle = String.Empty;
FileInfo oFile = null;
try
{
if (moFrmIntComplaint != null)
{
moFrmIntComplaint.cmndBrowseOpen.Filter = sFilter;
moFrmIntComplaint.cmndBrowseOpen.Title = ResourceHandler.Resources.GetString("BrowseFile:Title");
moFrmIntComplaint.cmdBrowseResult = moFrmIntComplaint.cmndBrowseOpen.ShowDialog();
string fileExtension = Path.GetExtension(moFrmIntComplaint.cmndBrowseOpen.FileName);
moFrmIntComplaint.cmndBrowseOpen.DefaultExt = ".pdf";
if (fileExtension != ".pdf")
{
moFrmIntComplaint.cmndBrowseOpen.FileOk += delegate(object s, System.ComponentModel.CancelEventArgs ev)
{
ev.Cancel = true;
};
}
if (String.IsNullOrEmpty(moFrmIntComplaint.cmndBrowseOpen.FileName) == false)
{
oFile = new FileInfo(moFrmIntComplaint.cmndBrowseOpen.FileName);
if ((oFile != null) && (File.Exists(moFrmIntComplaint.cmndBrowseOpen.FileName) && (fileExtension == ".pdf")))
{
if (Convert.ToDouble(oFile.Length) > dMaxFileSize)
{
sTitle = ResourceHandler.Resources.GetString("BrowseFile:FilSizTitle");
sMsg = ResourceHandler.Resources.GetString("BrowseFile:FileSize");
Cerner.Foundations.Measurement.TimedMessageBox.Show(sMsg, sTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
moFrmIntComplaint.lblFileName.Text = System.String.Empty;
moFrmIntComplaint.lblFilePath.Text = System.String.Empty;
moFrmIntComplaint.cmdRemove.Visible = false;
}
else
{
moFrmIntComplaint.lblFileName.Text = Path.GetFileName(moFrmIntComplaint.cmndBrowseOpen.FileName);
moFrmIntComplaint.lblFilePath.Text = moFrmIntComplaint.cmndBrowseOpen.FileName;
moFrmIntComplaint.cmdRemove.Left = moFrmIntComplaint.lblFileName.Left + moFrmIntComplaint.lblFileName.Width + 5;
moFrmIntComplaint.cmdRemove.Visible = true;
}
}
}
}
return;
}
The top three statements are in a different class called moFrmIntComplaint. As these variables are used in the browse_click method, this why I have mentioned these variables here. I have tried using delegate because of this question.
Even this doesn't help.
Related
I am new to learning C#, and i'm attempting to create a WPF application that asks the user questions. I then convert those answers into strings and export them to a CSV file.
One of the questions is "Pick a number between 1-5". I need to make this so that if a number is less than 1, or more than 5, it asks the user to pick a different number. I tried to achieve this by using the below code. It somewhat works because when i click save as, nothing will happen if i use a wrong number. But it doesn't ask the user like i want it to. Please could someone take a look at my code and let me know why this isn't working?
private void btnSaveClick(object sender, RoutedEventArgs e)
{
try
{
string firstName = tbFirstName.Text;
string lastName = tbLastName.Text;
string jobTitle = tbJobTitle.Text;
string chickenEgg = tbChickenEgg.Text;
string _oneFive = tbNumber.Text;
int oneFive = Convert.ToInt32(_oneFive);
if ((oneFive > 5) || (oneFive < 1))
{
throw new System.ArgumentException("Please use a number between 1-5");
}
string csvContent = string.Format("{0},{1},{2},{3},{4}", FormatCSV(firstName), FormatCSV(lastName), FormatCSV(jobTitle), FormatCSV(chickenEgg), FormatCSV(_oneFive));
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "CSV file (*.csv)|*.csv";
if (saveFileDialog.ShowDialog() == true)
File.WriteAllText(saveFileDialog.FileName, csvContent);
tbFirstName.Clear();
tbLastName.Clear();
tbJobTitle.Clear();
tbChickenEgg.Clear();
tbNumber.Clear();
tbFirstName.Focus();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
static string FormatCSV(string _input)
{
try
{
string result = "";
if ((_input.Contains(",")) || (_input.Contains(" ")))
{
result = string.Format("\"{0}\"", _input.Trim());
}
else
{
result = _input.Trim();
}
return result;
}
catch (Exception e)
{
throw e;
}
When i get to the catch block, nothing displays or seems to happen.
Thank you in advance!
Instead of throwing an exception, you could display a MessageBox to the user:
private void btnSaveClick(object sender, RoutedEventArgs e)
{
string firstName = tbFirstName.Text;
string lastName = tbLastName.Text;
string jobTitle = tbJobTitle.Text;
string chickenEgg = tbChickenEgg.Text;
string _oneFive = tbNumber.Text;
int oneFive = Convert.ToInt32(_oneFive);
if ((oneFive > 5) || (oneFive < 1))
{
MessageBox.Show("Please use a number between 1-5", "", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
string csvContent = string.Format("{0},{1},{2},{3},{4}", FormatCSV(firstName), FormatCSV(lastName), FormatCSV(jobTitle), FormatCSV(chickenEgg), FormatCSV(_oneFive));
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "CSV file (*.csv)|*.csv";
if (saveFileDialog.ShowDialog() == true)
File.WriteAllText(saveFileDialog.FileName, csvContent);
tbFirstName.Clear();
tbLastName.Clear();
tbJobTitle.Clear();
tbChickenEgg.Clear();
tbNumber.Clear();
tbFirstName.Focus();
}
}
The user can then click "OK" to dismiss the message box and then enter a new number and hit the "Save" button again. This is basically how GUI applications tend to work.
If you want to tell the user something, the simple way to do it is with a message box
MessageBox.Show("enter a number between 1 and 5");
A better, but a little bit more complicated is to use binding validation. This will reject input as soon as it is entered.
It might be a good idea to read Best practices for exceptions, one rule is to handle common conditions without throwing exceptions, and an incorrect input value would be one of these common cases.
I am using this code to monitor creation of files in certain folder:
_watcher = new RecoveringFileSystemWatcher(SourceFolder, "*.xml");
_watcher.Created += (_, e) =>
{
ProcessFile(e.Name);
};
RecoveringFileSystemWatcher is a fileSystemWatcher wrapper. It's constructor is:
public RecoveringFileSystemWatcher (string path, string filter)
{
_containedFSW = new FileSystemWatcher(path, filter);
}
The process works as expected but for some files, randomly, an exception is thrown telling that the file is used by another process.
This is the method that is launched upon file creation:
var nfo = new FileInfo(filePath);
if (nfo.Exists)
{
var archivoXml = nfo.Name;
string archivo = String.Empty;
try
{
string content = Task.Run(async () => await GetFileContent(filePath)).Result;
if (String.IsNullOrEmpty(content))
return false;
XmlDocument xml = new XmlDocument();
xml.LoadXml(content);
//The rest of the method
}
}
the method GetFileContent is this:
private async Task<string> GetFileContent(string filePath)
{
string content = String.Empty;
try
{
Console.Write("ONE - "); InfoLog.Save($"ONE {filePath}");
using (StreamReader sr = new StreamReader(filePath))
{
Console.Write("TWO - "); InfoLog.Save($"TWO {filePath}");
content = await sr.ReadToEndAsync().ConfigureAwait(false);
Console.Write($"THREE {(sr.BaseStream == null ? "Closed" : "Opened")} - "); InfoLog.Save($"THREE {(sr.BaseStream == null ? "Closed" : "Opened")} {filePath}");
sr.Close();
Console.WriteLine($"FOUR {(sr.BaseStream == null ? "Closed" : "Opened")}"); InfoLog.Save($"FOUR {(sr.BaseStream == null ? "Closed" : "Opened")} {filePath}");
}
}
catch (Exception ex)
{
InfoLog.Save($"XML file could be read -> {filePath}. See error log.");
ErrorLog.Save(ex);
}
return content;
}
Look at the log information I am writing to debug the process.
I got one case with a file called 1112186.xml.... this is recorded in the log:
18/12/2018 19:12:10 ONE D:\GestorDocumental\Origen\1112186.xml
18/12/2018 19:12:10 XML file could not be read -> D:\GestorDocumental\Origen\1112186.xml. See error log.
As you see, the exception is thrown at the "using" instruction.
If I see the full log, I can see that file, 1112186.xml, is never used before, so the only chance is that FSW keeps the file opened. I don't know why, but it seems this is happening.
It is clear also that this process is locking the file, because when I exit the console application and then run again, the file can be processed.
Any help about this, please?
thanks
Jaime
I usually use this method to check if file is locked. I got it from one of the link in stackoverflow.
public static bool IsFileClosed(string filepath)
{
bool fileClosed = false;
int retries = 20;
const int delay = 400; // set a delay period = retries*delay milliseconds
if (!File.Exists(filepath))
return false;
do
{
try
{
// Attempts to open then close the file in RW mode, denying other users to place any locks.
FileStream fs = File.Open(filepath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
fs.Close();
fileClosed = true; // success
}
catch (IOException) { }
retries--;
if (!fileClosed)
Thread.Sleep(delay);
}
while (!fileClosed && retries > 0);
return fileClosed;
}
This is a new class called FileTimerWatcher (it will have logger injected):
public FileTimerWatcher(ILogger logger) : base(logger)
{
if (timer == null)
{
// Create a timer with a 1.5 second interval.
// monitor the files after 1.5 seconds.
timer = new Timer(delay);
// Hook up the event handler for the Elapsed event.
timer.Elapsed += new ElapsedEventHandler(ProcessFolder);
timer.AutoReset = true;
timer.Enabled = true;
}
}
private void ProcessFolder(object sender, ElapsedEventArgs e)
{
var LastChecked = DateTime.Now;
string[] files = System.IO.Directory.GetFiles(SourceDirectory, somefilter, System.IO.SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
ProcessFile(file); // process file here
}
}
I have a background worker that I use to create files in the background.
I had it working so that the files were created and the UI was still responsive.
I made some changes and now I can't figure out why the background worker is locking my main thread.
Here are my background worker methods. I don't have a progress changed event.
private void filecreator_bgw_DoWork(object sender, DoWorkEventArgs e)
{
if (filecreator_bgw.CancellationPending == true)
{
e.Cancel = true;
}
else
{
myManager.createFiles((SelectedFileTypes) e.Argument);
}
}
private void filecreator_bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == true)
{
//status_label.Text = "Canceled!";
}
else if (e.Error != null)
{
//status_label.Text = "Error: " + e.Error.Message;
}
else
{
// Check the file manager object to see if the files were created successfully
status_label.Text = "COMPLETE";
file_statusLabel.Text = "Files Created: " + DateTime.Now.ToShortTimeString();
System.Threading.Thread.Sleep(5000);
status_label.Text = "Click Create Files to Begin";
createfiles_button.Enabled = true;
}
}
Here is the method to create the files.
public void createFiles(SelectedFileTypes x)
{
if (string.IsNullOrEmpty(Filename) || (x.isCSV == false && x.isTAB == false && x.isXML == false))
{
filesCreated = false;
return;
}
// Declare the streams and xml objects used to write to the output files
XDocument xmlFile;
StreamWriter swCSV;
StreamWriter swTAB;
CSVFilename = Path.GetDirectoryName(Filename) + Path.DirectorySeparatorChar.ToString() +
Path.GetFileNameWithoutExtension(Filename) + "CSV_TEST.csv";
swCSV = new StreamWriter(CSVFilename);
TABFilename = Path.GetDirectoryName(Filename) + Path.DirectorySeparatorChar.ToString() +
Path.GetFileNameWithoutExtension(Filename) + "TAB_TEST.csv";
swTAB = new StreamWriter(TABFilename);
XMLFilename = Path.GetDirectoryName(Filename) + Path.DirectorySeparatorChar.ToString() +
Path.GetFileNameWithoutExtension(Filename) + "XML_TEST.csv";
xmlFile = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment("Crosswalk"));
xmlFile.Add(new XElement("ACCOUNTS"));
// String array for use when creating xml nodes
string[] splits;
// String used to read in a line from the input file
string line = "";
// Use a try and catch block, if any errors are caught, return false
try
{
// Read each line in the file and write to the output files
using (StreamReader sr = new StreamReader(Filename))
{
int i = 0;
while ((line = sr.ReadLine()) != null)
{
if (x.isCSV)
{
swCSV.WriteLine(line.Replace(delim, ","));
}
if (x.isTAB)
{
swTAB.WriteLine(line.Replace(delim, "\t"));
}
if (x.isXML)
{
if (i <= 0)
{
i++;
continue;
}
splits = line.Split(new string[] { delim }, StringSplitOptions.RemoveEmptyEntries);
xmlFile.Root.Add(
new XElement("ACCOUNTS",
from s in header
select new XElement(s, splits[Array.IndexOf(header, header.Where(z => z.Equals(s, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault())])
)
);
}
}
// Dispose of all objects
swCSV.Close();
swCSV.Dispose();
swTAB.Close();
swTAB.Dispose();
if (x.isXML)
{
//xmlFile.Save(Path.GetFullPath(Filename) + Path.GetFileNameWithoutExtension(Filename) + "_TEST.xml");
xmlFile.Save(XMLFilename);
}
}
}
catch (Exception)
{
filesCreated = false;
return;
}
// Return true if file creation was successfull
filesCreated = true;
}
In the do work method, I build a simple struct to determine what output file types should be made and then I pass it to the method. If I comment out that call to create the files, the UI still does not respond.
In the create files method, I build out the files based on the input file that I am transforming. I do use a LINQ statement to help build out XML tags, but the arrays holding the tags values are small, 3-5 elements depending on the file chosen.
Is there a simple solution, or should I re-design the method. If I have to re-design, what are things I should keep in mind to avoid locking the main thread.
Thanks
Here is how I call the runworkerasync method:
private void createfiles_button_Click(object sender, EventArgs e)
{
SelectedFileTypes selVal = new SelectedFileTypes();
foreach (var structVal in outputformats_checkedListBox.CheckedItems)
{
if (structVal.ToString().Equals("CSV", StringComparison.InvariantCultureIgnoreCase))
selVal.isCSV = true;
if (structVal.ToString().Equals("TAB", StringComparison.InvariantCultureIgnoreCase))
selVal.isTAB = true;
if (structVal.ToString().Equals("XML", StringComparison.InvariantCultureIgnoreCase))
selVal.isXML = true;
}
// Call the FileManager object's create files method
createfiles_button.Enabled = false;
filecreator_bgw.RunWorkerAsync(selVal);
}
UPDATE:
I updated the call to start the worker and then the call to create the files using the argument passed into the worker.
You cannot interact with most UI controls directly from a BackgroundWorker. You need to access outputformats_checkedListBox.CheckedItems from the UI thread and pass the resulting SelectedFileTypes object into the BackgroundWorker as a parameter.
Also, pleas enote that your cancellation logic really didn't do much. In order for it to work well, you need to check CancellationPending throughout the process, not just when starting.
Here is a rough example of how you should start the worker:
private void StartWorker()
{
SelectedFileTypes selVal = new SelectedFileTypes();
foreach (var structVal in outputformats_checkedListBox.CheckedItems)
{
if (structVal.ToString().Equals("CSV", StringComparison.InvariantCultureIgnoreCase))
selVal.isCSV = true;
if (structVal.ToString().Equals("TAB", StringComparison.InvariantCultureIgnoreCase))
selVal.isTAB = true;
if (structVal.ToString().Equals("XML", StringComparison.InvariantCultureIgnoreCase))
selVal.isXML = true;
}
filecreator_bgw.RunWorkerAsync(selVal);
}
private void filecreator_bgw_DoWork(object sender, DoWorkEventArgs e)
{
SelectedFileTypes selVal = (SelectedFileTypes)e.Argument;
myManager.createFiles(selVal);
}
I have the following code:
Open File Code
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "Open File";
ofd.FileName = "";
ofd.Filter = "Rich Text Files (*.rtf)|*.rtf|Text Document (*.txt)|*.txt|Microsoft Word Document (*.doc)|*.doc|Hypertext Markup Language Document (*.html)|*.html"; StreamReader sr = null;
if (ofd.ShowDialog() != DialogResult.Yes) return;
{
NewFile();
}
try
{
sr = new StreamReader(ofd.FileName);
this.Text = string.Format("{0} - Basic Word Processor", Path.GetFileName(ofd.FileName));
richTextBoxPrintCtrl1.Text = ofd.FileName;
richTextBoxPrintCtrl1.Text = sr.ReadToEnd();
filepath = ofd.FileName;
richTextBoxPrintCtrl1.LoadFile(fileName, RichTextBoxStreamType.RichText);
}
catch
{
}
finally
{
if (sr != null) sr.Close();
}
New File Code
if (richTextBoxPrintCtrl1.Modified)
{
DialogResult r = MessageBox.Show(this, "Save Current Document?", "Save?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (r == DialogResult.Yes) SaveFile();
if (r == DialogResult.Cancel) return;
}
this.Text = string.Format("Untitled - Basic Word Processor");
richTextBoxPrintCtrl1.Text = "";
filepath = null;
}
}
SaveFileAs Code
SaveFileDialog sfdSaveFile = new SaveFileDialog();
sfdSaveFile.Title = "Save File";
sfdSaveFile.FileName = "Untitled";
sfdSaveFile.Filter = "Rich Text Files (*.rtf)|*.rtf|Text Document (*.txt)|*.txt|Microsoft Word Document (*.doc)|*.doc|Hypertext Markup Language Document (*.html)|*.html";
if (sfdSaveFile.ShowDialog() == DialogResult.OK)
try
{
filepath = sfdSaveFile.FileName;
SaveFile();
this.Text = string.Format("{0} - Basic Word Processor", Path.GetFileName(sfdSaveFile.FileName));
}
catch (Exception exc)
{
}
SaveFile Code
if (filepath == null)
{
SaveFileAs();
return;
}
StreamWriter sw = new StreamWriter(filepath);
//StreamWriter stwrite = null;
try
{
sw.WriteLine(richTextBoxPrintCtrl1.Text);
richTextBoxPrintCtrl1.Modified = false;
sw.Close();
}
catch (Exception e)
{
MessageBox.Show("Failed to save file. \n" + e.Message);
}
finally
{
if (sw != null) sw.Close();
}
Currently, the program skips the NewFile event (even if the text has been modified). How can I make it so that when I click "Open", it asks me if I would like to save (if the text is modified). Then if I click cancel, it returns me to the form?
Sorry. I'm really new to programming so this is all a learning curve.
Okay, I think I see what's going on here. First off I don't believe return; works the way you think it does.
if (ofd.ShowDialog() != DialogResult.Yes) return;
{
NewFile();
}
You have a return; call that happens if the show dialog is not yes. The { newFile() } code doesn't need braces around it. So those lines are really:
if (ofd.ShowDialog() != DialogResult.Yes) return;
NewFile();
Now, given your requirement, NewFile is called WAY too late in the game anyway. You want that to happen before you ask them what to open; just like most other windows programs work.
But, there's another issue. Your return statement in the NewFile method is simply returning from NewFile. It's not telling the previous method to bail out.
So the NewFile method needs a return type to indicate whether to allow the calling method to go forward or not.
And, looking at your save file you have a return method there too. What's with all of the return; calls?
Which brings us back to how do we fix this?
Answer: rewrite the whole thing. Starting with the following method:
private Boolean CanClear() {
Boolean result = false;
if (richTextBoxPrintCtrl1.Modified)
{
DialogResult r = MessageBox.Show(this, "Save Current Document?", "Save?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (r == DialogResult.Yes) {
SaveFile();
result = true;
}
} else {
result = true;
}
return result;
}
Now, in your Open and New file methods do the following (assuming these are the method headers)
protected void OpenFile(...) {
if (!CanClear()) return;
.... now execute the code to load the open dialog and the selected file.
}
protected void NewFile(...) {
if (!CanClear()) return;
this.Text = string.Format("Untitled - Basic Word Processor");
richTextBoxPrintCtrl1.Text = "";
filepath = null;
}
The problem is here:
if (ofd.ShowDialog() != DialogResult.Yes) return;
{
NewFile();
}
remove that return. But, as #Chris says, you should ask whether to save the current file or not before the user selects the new file to open.
MonoDevelop (2.10.8) is reporting:
JPGCorruptForm.cs(20,20): Warning CS0219: The variable `myStream' is assigned but its value is never used (CS0219) (JPGCorrupt)
For this function:
private void toolStripButtonChooseText_Click(object sender, EventArgs e)
{
Stream myStream = null;
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.InitialDirectory = ".";
openFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
openFileDialog.FilterIndex = 1;
openFileDialog.RestoreDirectory = false;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
Stop();
try
{
if ((myStream = openFileDialog.OpenFile()) != null)
{
_settings.TextFile = openFileDialog.FileName;
CurrentTextFile = _settings.TextFile;
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
}
This is my frist mono test project and I'm not sure if this kind of thing is normal. It certainly is not fatal, but could get annoying.
Well you're assigning a value to the variable, but you're never actually reading from it. In other words, you could easily remove it, just changing the middle expression to:
if (openFileDialog.OpenFile() != null)
Note that your existing code doesn't actually read from the variable even though you might think it does in the comparison to null. It's more like this:
Stream tmp = openFileDialog.OpenFile();
myStream = tmp;
if (tmp != null)
It sounds like you probably should be using it, to close the stream if nothing else... although I'd then declare it as late as possible, like this:
using (Stream myStream = openFileDialog.OpenFile())
{
if (myStream != null)
{
_settings.TextFile = openFileDialog.FileName;
CurrentTextFile = _settings.TextFile;
}
}
Here's a simpler example of the same problem, but the way:
using System;
class Test
{
static void Main()
{
string x;
if ((x = "Hello") != null)
{
Console.WriteLine("Yes");
}
}
}
Note that with warning level 4 (and possibly lower ones), the Microsoft C# 4 compiler picks up on it too:
Test.cs(7,16): warning CS0219: The variable 'x' is assigned but its value is
never used