I have read so many bed time stories and ins and outs of how delegates work and why events are to be replaced with delegates (surely not all the time) and just couldn't get my head around it.
I am trying to use delegates in a more functional way in my code rather than practice runs in the LinqPad with dummy examples and this is my first go.
In this case I have a FileManager
helper class which I can reach out anytime and use it to bring up the Open File Dialog
with the retry functionality if the file is still locked and under use.
In one stage I was doing different operations with the file received through the OpenFileDialog
so I decided to pass the functionality through a delegate to my FileManager.Open()
method.
First of all, let me know if I am implementing this using delegates
the right way.
In the next step, I am eager to learn what would I earn from transforming this delegate
to an event
in this particular case and how would I do that?
FileManager.cs
public class FileManager
{
public delegate string DoWithFile(string file);
/// <summary>
/// Brings the Open File Dialog and asks the user to choose
/// the file. Also handles the exceptions.
/// </summary>
/// <param name="title"></param>
/// <param name="fileType"></param>
/// <returns></returns>
public static string Open(string title, string fileType, DoWithFile doWithFile)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.DefaultExt = "." + fileType;
openFileDialog.Filter = string.Format("Excel file (*.{0})|*.{0}", fileType);
openFileDialog.RestoreDirectory = false;
openFileDialog.Title = title;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
if (FileIsReady(openFileDialog.FileName))
return doWithFile(openFileDialog.FileName);
//return openFileDialog.FileName;
}
return null;
}
/// <summary>
/// Checks to see if the file is ready to be used
/// meaning it's not locked since being open etc.
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private static bool FileIsReady(string fileName)
{
try
{
if (fileName != null)
{
// This is to make sure if the file isn't open atm.
using (Stream stream = new FileStream(fileName, FileMode.Open))
{
return true;
}
}
}
catch (IOException)
{
// Retry mechanism
if (System.Windows.Forms.MessageBox.Show(
"Error: Could not read file from disk.\r\n" +
"Try closing the file if it is still open and try again.",
"Cannot open the file",
MessageBoxButtons.RetryCancel,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1
) == DialogResult.Retry)
{
return FileIsReady(fileName);
}
}
return false;
}
}
MainWindowViewModel.cs
/// <summary>
/// Opens the FileOpenDialog and asks the user to choose the pricing
/// spreadsheet.
/// </summary>
/// <returns></returns>
private string ChoosePricingSpreadsheet()
{
// Parameters are OpenFileDialog header, file type filtered and Delegate
return FileManager.Open("Select the pricing spreadsheet", "xlsx", doWithFileHandler);
}
// Instantiating the delegate with the method we want to be passed to FileManager.Open
FileManager.DoWithFile doWithFileHandler = ReturnFileIfReady;
/// <summary>
/// The action need to be done with the file opened using FileManager.Open
/// In this case we want the file which user have chosen in the
/// OpenFileDialog to be passed to the program.
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
private static string ReturnFileIfReady(string file)
{
return file;
}
FileManager.Open(title, fileType, doWithFileHandler)
instead ofdoWithFileHandler(FileManager.Open(title, fileType))
? Is it just to simplify handling nulls? \$\endgroup\$OpenFileDialog
implementsIDisposable
and thus its lifetime should be wrapped in ausing
construct. \$\endgroup\$