File not getting saved in specified location in winforms c# - c#

Eventhough i specify a different location the file gets saved in mydocuments. How to resolve this issue. Pls share your ideas if any.Here is the code.
if (externalButton.Checked == true)
{
// int i = 1;
saveFileDialog.Title = "Save the Proofer Report";
saveFileDialog.Filter = "Document Files (*.doc)|*.doc|Document Files (*.docx)|*.docx";
saveFileDialog.FilterIndex = 0;
saveFileDialog.InitialDirectory = "MyDocuments";
saveFileDialog.FileName = "Proofer Report -- " + Path.GetFileName((string)fileName) + ".doc";
//i.tostring()
saveFileDialog.DefaultExt = ".doc";
saveFileDialog.ShowHelp = true;
// saveFileDialog.ShowDialog();
var thread = new Thread(new ParameterizedThreadStart(param => { saveFileDialog.ShowDialog(); }));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
fname = saveFileDialog.FileName;

You are showing dialog assynchronously on new thread and code after starting the thread executes before dialog is shown (most of the time).
Either wait for thread completion or move saving to that thread after dialog is closed.

Why You Are Showing saveFileDialog in different thread?
if you show save dialog in diffrent thread fname = saveFileDialog.FileName; is always return null.dont use separate thread.or Call this event after thread start
saveFileDialog1.FileOk += new CancelEventHandler(saveFileDialog1_FileOk);
void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
{
string fname = null;
fname = saveFileDialog1.FileName;
}
Edited
Example
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
_SaveFileDialog.FileOk += new CancelEventHandler(_SaveFileDialog_FileOk);
}
string filename = null;
SaveFileDialog _SaveFileDialog = new SaveFileDialog();
private void savebtn_Click(object sender, EventArgs e)
{
_SaveFileDialog.Title = "Save the Proofer Report";
_SaveFileDialog.Filter = "Document Files (*.doc)|*.doc|Document Files (*.docx)|*.docx";
_SaveFileDialog.FilterIndex = 0;
_SaveFileDialog.InitialDirectory = "MyDocuments";
_SaveFileDialog.FileName = "Proofer Report -- .doc";
_SaveFileDialog.DefaultExt = ".doc";
_SaveFileDialog.ShowHelp = true;
var thread = new Thread(new ParameterizedThreadStart(param => { _SaveFileDialog.ShowDialog(); }));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
void _SaveFileDialog_FileOk(object sender, CancelEventArgs e)
{
filename = _SaveFileDialog.FileName;
}
}

Related

How to fix access denial error when copying an excel file programmatically within a thread in C#

I'm writing a program which copies an excel file to another location and removes the sheets except for the visible sheets and saving the copied file. I have used the BackgroundWorker class in order to achieve this.
First, I initialized the Background Worker methods.
private void InitializeBackgroundWorker()
{
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
}
"BackgroundWorker.DoWork()" method is as follows.
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
GenerateReports(worker);
// Cancel the asynchronous operation.
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
worker.ReportProgress(100);
if(backgroundWorker.IsBusy)
{
this.backgroundWorker.CancelAsync();
}
}
The "GenerateReports()" method contains the "ExtractVisibleSheets()" method which extracts the visible sheets, which then calls the "CopyVisibleSheets()" method.
private void ExtractVisibleSheets(String originalDirectory, String convertedDirectory)
{
//Get the .xlsx files of the original reports and the converted reports
visibleSheetsOriginal = Directory.GetFiles(originalDirectory, "*.xlsx");
visibleSheetsConverted = Directory.GetFiles(convertedDirectory, "*.xlsx");
//Copy the visible sheets to the defined workbooks
//Sample Reports
CopyVisibleSheets(originalDirectory, visibleSheetsOriginal, visibleSheetsBasePath);
//Converted Reports
CopyVisibleSheets(convertedDirectory, visibleSheetsOriginal, visibleSheetsConvertedPath);
}
private void CopyVisibleSheets(String directory, String[] excelFiles, String path)
{
excelApplication = null;
workbook = null;
Excel.Worksheet sheet = null;
String copiedReport = "";
try
{
foreach(String report in excelFiles)
{
copiedReport = path + "\\" + report.Substring(report.LastIndexOf('\\') + 1);
excelApplication = GetExcelApplication();
File.Copy(report, copiedReport);
OpenXmlFileProcessor.RemoveCustomProperty(copiedReport, FileProcessor.BaClientVerParam);
workbook = excelApplication.Workbooks.Open(copiedReport);
EnableDisableAlertsAndEvents(false);
for (int i = workbook.Worksheets.Count; i > 0; i--)
{
sheet = excelApplication.ActiveWorkbook.Worksheets[i];
if(sheet.Visible != XlSheetVisibility.xlSheetVisible)
{
sheet.Visible = XlSheetVisibility.xlSheetVisible;
sheet.Delete();
}
}
workbook.Save();
EnableDisableAlertsAndEvents(true);
workbook.Close();
Marshal.ReleaseComObject(workbook);
}
}
finally
{
QuitAndReleaseExcelApplication(false);
}
}
"BackgroundWorker.RunWorkerCompleted()" method is given below
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
// Next, handle the case where the user cancelled
// the operation.
}
else
{
// Finally, handle the case where the operation
// succeeded.
MessageBox.Show("Directory Generation Successful!");
}
EnableControls();
}
But an error occurs during the line "File.Copy(report, copiedReport)" as follows and is fired up from the "BackgroundWorker.RunWorkerCompleted()" method.
Error
Do let me know if someone knows the reason for this error.
As a rule, the system C: drive requires admin privileges for writing. I'd suggest choosing another drive or folder (application data).
path + "\\" + report.Substring(report.LastIndexOf('\\') + 1);
try to use double qute "" (report.LastIndexOf('\\') + 1);
its a type of strings
try to use path + "//" + report.Substring(report.LastIndexOf("//") + 1);
correct me if im wrong :)

Increment ProgressBar within another class

it's my first question I'm asking here, so please be gentle with me ;)
So I've actually got two WinForms in my C# application I'm writing at the moment (I'm quite new to C#).
This window has a button, which saves photos from an usb device you selected before in a list box to another folder.
After clicking on this button my main thread is of course busy with copying, so I decided to create another WinForm which contains my ProgressBar.
Foreach completed copy, I want to increment my ProgressBar accordingly.
So I count the number of copies I have to do and give it the progressbar as maximum. But my problem at the moment is, that I really don't know how to increment the ProgressBar without getting a Thread Unsafe Exception.
Here's my ProgressWindow code:
public partial class ProgressWindow : Form
{
BackgroundWorker updateProgressBarThread = new BackgroundWorker();
private Boolean _isThreadRunning = false;
public Boolean IsThreadRunning
{
get { return _isThreadRunning; }
set { _isThreadRunning = value; }
}
private int _progressbarLength;
public int ProgressbarLength
{
get { return _progressbarLength; }
set { _progressbarLength = value; }
}
private int progress = 1;
public ProgressWindow()
{
Show();
InitializeComponent();
}
private void StartUpdateThread(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
// Reports progress to the ProgressChangedEvent function. (Thread Safe)
}
private void FinishProgressThread(object sender, RunWorkerCompletedEventArgs e)
{
if (!_isThreadRunning)
{
MessageBox.Show("Erfolgreich kopiert");
Close();
}
}
private void ProgressChangedEvent(object sender, ProgressChangedEventArgs e)
{
this.copyProgressbar.Value = e.ProgressPercentage;
this.progressStatus.Text = e.ProgressPercentage.ToString();
}
public void CallUpdateThread()
{
updateProgressBarThread.WorkerReportsProgress = true;
updateProgressBarThread.DoWork += new DoWorkEventHandler(StartUpdateThread);
updateProgressBarThread.ProgressChanged += new ProgressChangedEventHandler(ProgressChangedEvent);
updateProgressBarThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(FinishProgressThread);
updateProgressBarThread.RunWorkerAsync();
}
}
I want to increment my ProgressBar with 1 after each succesful copy.
How do I do this from my main thread?
This is the function which actually handles the copy process
private void SaveFile(System.IO.DirectoryInfo root)
{
try
{
IEnumerable<DirectoryInfo> directoriesNames = root.EnumerateDirectories();
// New instance of thread ProgressWindow.
ProgressWindow progress = new ProgressWindow();
progress.CallUpdateThread();
foreach (DirectoryInfo element in directoriesNames)
{
// Query all subdirectories and count everything with the in the configuration made settings.
if (!element.Attributes.ToString().Contains("System"))
{
// Now we insert the configuration we applied.
String fileExtension = null;
if (Properties.Settings.Default._configPhoto)
{
fileExtension = "*.jpg";
}
if (Properties.Settings.Default._configWordDocument)
{
fileExtension = "*.odt";
}
FileInfo[] jpgList = element.GetFiles(fileExtension, SearchOption.AllDirectories);
// set the size of the progress bar
progress.ProgressbarLength = jpgList.Count();
// Now we go through all our results and save them to our backup folder.
foreach (FileInfo tmp in jpgList)
{
string sourceFilePath = tmp.FullName;
string destFilePath = PATHTOBACKUP + "\\" + tmp.Name;
progress.IsThreadRunning = true;
try
{
System.IO.File.Copy(sourceFilePath, destFilePath, true);
}
catch (IOException ioe)
{
MessageBox.Show(ioe.Message);
}
}
}
}
// progress.IsThreadRunning = false;
}
catch (UnauthorizedAccessException e)
{
MessageBox.Show(e.Message);
}
}
It's pretty obvious that I have to do this after this function
System.IO.File.Copy(sourceFilePath, destFilePath, true);
But how do I report this to my ProgressWindow?
I really hope I explained it well enough, not sure if I'm missing something important.
Thanks in advance guys
Here is a compact example of the key components:
Clicking button starts new thread worker
Progress is done by file lengths, not by number of files
BeginInvoke used to update the progress bar (avoid cross Thread exception)
ProgressBar pb = new ProgressBar() { Minimum = 0, Maximum = 100 };
Button btn = new Button();
btn.Click += delegate {
Thread t = new Thread(() => {
DirectoryInfo dir = new DirectoryInfo("C:\\temp\\");
var files = dir.GetFiles("*.txt");
long totalLength = files.Sum(f => f.Length);
long length = 0;
foreach (var f in files) {
length += f.Length;
int percent = (int) Math.Round(100.0 * length / totalLength);
pb.BeginInvoke((Action) delegate {
pb.Value = percent;
});
File.Copy(f.FullName, "...");
}
});
t.IsBackground = true;
t.Start();
};

Using a label to depict the status of a form

I have a situation where all I need is a label that switches between "Ready" and "In progress" when a user clicks a button. The label is intially in the "Ready" state. When the user clicks a button, the label should read "In progress" then some tasks need to be performed, like copying files etc. After the tasks are completed successfully the label should once again read "Ready". Right now I am using this piece of code and the label status does not change. How can I make this work. Please help.
private void button1_Click(object sender, EventArgs e)
{
status.Text = "In Progress";
if (listBox1.Items.Count == 0)
{
MessageBox.Show("Please select a file to upload");
}
FtpClient client = new FtpClient("*******", "*******", "******");
string fileName = getFileNameFromPath(listBox1.Items[0].ToString());
string localFile = listBox1.Items[0].ToString();
string remoteFile = "**********/"+fileName;
string link = client.upload(remoteFile, localFile);
listBox1.Items.RemoveAt(0);
textBox1.Text = link;
status.Text = "Ready";
}
You're blocking the UI thread during your long running process, both preventing the UI from updating the text value, or receiving user input, or doing anything for that matter.
You need to do the long running work asynchronously so as to not block the UI thread.
Ideally you'd have an asynchronous method provided by your FtpClient (and even better, it would return a Task). This would allow you to write something like this:
private async void button1_Click(object sender, EventArgs e)
{
status.Text = "In Progress";
if (listBox1.Items.Count == 0)
{
MessageBox.Show("Please select a file to upload");
}
FtpClient client = new FtpClient("*******", "*******", "******");
string fileName = getFileNameFromPath(listBox1.Items[0].ToString());
string localFile = listBox1.Items[0].ToString();
string remoteFile = "**********/" + fileName;
string link = await client.uploadAsync(remoteFile, localFile);
listBox1.Items.RemoveAt(0);
textBox1.Text = link;
status.Text = "Ready";
}
And then you'd be done. If it doesn't provide any asynchronous methods then, as a work around, you can just start up a new task to do the work in the background:
private async void button1_Click(object sender, EventArgs e)
{
status.Text = "In Progress";
if (listBox1.Items.Count == 0)
{
MessageBox.Show("Please select a file to upload");
}
FtpClient client = new FtpClient("*******", "*******", "******");
string fileName = getFileNameFromPath(listBox1.Items[0].ToString());
string localFile = listBox1.Items[0].ToString();
string remoteFile = "**********/" + fileName;
string link = await Task.Run(() => client.upload(remoteFile, localFile));
listBox1.Items.RemoveAt(0);
textBox1.Text = link;
status.Text = "Ready";
}
If you don't have C# 5.0 and .NET 4.5 to be able to use await then you can use a BackgroundWorker:
private void button1_Click(object sender, EventArgs e)
{
status.Text = "In Progress";
if (listBox1.Items.Count == 0)
{
MessageBox.Show("Please select a file to upload");
}
string fileName = getFileNameFromPath(listBox1.Items[0].ToString());
string localFile = listBox1.Items[0].ToString();
string remoteFile = "**********/" + fileName;
var worker = new BackgroundWorker();
worker.DoWork += (s, args) =>
{
FtpClient client = new FtpClient("*******", "*******", "******");
args.Result = client.upload(remoteFile, localFile);
};
worker.RunWorkerCompleted += (s, args) =>
{
listBox1.Items.RemoveAt(0);
textBox1.Text = args.Result as string;
status.Text = "Ready";
};
worker.RunWorkerAsync();
}

Showing Dialog After Long Process

In the following code, I have a long running process called GetExcelData. When it's complete, I want to show a dialog to save it's contents into a TXT file.
The problem is, when debugging, I get the following error:
Current thread must be set to single thread apartment (STA) mode
before OLE calls can be made. Ensure that your Main function has
STAThreadAttribute marked on it. This exception is only raised if a
debugger is attached to the process.
This is my code. The error occurs on the line that reads saveFileDialog1.ShowDialog();
FileInfo existingFile = new FileInfo("C:\\MyExcelFile.xlsx");
ConsoleApplication2.Program.ExcelData data = ConsoleApplication2.Program.GetExcelData(existingFile, _worker);
var json = new JavaScriptSerializer().Serialize(data);
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
saveFileDialog1.ShowDialog();
if (saveFileDialog1.FileName != "")
{
File.WriteAllText(saveFileDialog1.FileName, json);
}
I have tried adding the [STAThread] attribute to the method I am calling this from but it didn't seem to work.
Please let me provide more code for additional clarity as to what I am trying to do:
The following exists in a WPF project which references my Console project:
private BackgroundWorker _backgroundWorker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
// Set up the BackgroundWorker.
this._backgroundWorker.WorkerReportsProgress = true;
this._backgroundWorker.WorkerSupportsCancellation = true;
this._backgroundWorker.DoWork += new DoWorkEventHandler(bw_DoWork);
this._backgroundWorker.ProgressChanged +=
new ProgressChangedEventHandler(bw_ProgressChanged);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (this._backgroundWorker.IsBusy == false)
{
this._backgroundWorker.RunWorkerAsync();
}
e.Handled = true;
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Set the Value porperty when porgress changed.
this.progressBar1.Value = (double)e.ProgressPercentage;
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker _worker = sender as BackgroundWorker;
if (_worker != null)
{
FileInfo existingFile = new FileInfo("C:\\MyExcelFile.xlsx");
ConsoleApplication2.Program.ExcelData data = ConsoleApplication2.Program.GetExcelData(existingFile, _worker);
var json = new JavaScriptSerializer().Serialize(data);
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
saveFileDialog1.ShowDialog();
if (saveFileDialog1.FileName != "")
{
File.WriteAllText(saveFileDialog1.FileName, json);
}
}
}
Move the code that interacts with the UI to the same thread that handle your UI elements. The easiest way to do so it through the RunWorkerCompleted event
this._backgroundWorker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(bw_WorkComplete);
....
void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker _worker = sender as BackgroundWorker;
if (_worker != null)
{
FileInfo existingFile = new FileInfo("C:\\MyExcelFile.xlsx");
ConsoleApplication2.Program.ExcelData data = ConsoleApplication2.Program.GetExcelData(existingFile, _worker);
e.Result = new JavaScriptSerializer().Serialize(data);
}
}
private void bw_WorkComplete(object sender, RunWorkerCompletedEventArgs e)
{
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
saveFileDialog1.ShowDialog();
if (saveFileDialog1.FileName != "")
{
string json = e.Result.ToString();
File.WriteAllText(saveFileDialog1.FileName, json);
}
}
In the DoWork method, save the json string in the e.Result property of the DoWorkEventArgs class and retrieve it in the RunWorkerCompleted event from the RunWorkerCOmpletedEventArgs property with the same name.
Why?
Basically what happens is that you call saveFileDialog1.ShowDialog(); from bw_DoWork. And that's not right. Dialog is the UI control and should run from the UI thread and bw_DoWork method is executed in a separate thread (which is non-UI).
How to fix this?
Move the dialog show code away from the bw_DoWork method and pass the needed string instead. So the algorithm would look like
Click a button or whatever action to show the dialog [UI thread]
Open dialog [UI thread]
Verify you get a valid string from the dialog [UI thread]
Start background worker and pass a file path string [UI thread]
Write to file [background worker thread]
Modify your Program.cs so the declaration of the Main method looks like this:
[STAThread]
static void Main()

C# ListBox Import from Text File Crash

I am using this code to import text file to my ListBox
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Text Files|*.txt";
openFileDialog1.Title = "Select a Text file";
openFileDialog1.FileName = "";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
string file = openFileDialog1.FileName;
string[] text = System.IO.File.ReadAllLines(file);
foreach (string line in text)
{
listBox2.Items.Add(line);
}
listBox2.Items.Add("");
}
It works fine for small text files, with 10 lines or so, but when I try to import bigger list, (4-5 megabytes) the program isn't responding and it's crashing.
Any help?
Use the BufferedStream class in C# to improve performance.
http://msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx
By using this:
string[] text = System.IO.File.ReadAllLines(file);
listBox1.Items.AddRange(text);
instead of this:
string[] text = System.IO.File.ReadAllLines(file);
foreach (string line in text)
{
listBox2.Items.Add(line);
}
you will speed up the execution at least 10-15 times because you are not invalidating listBox on every Item insert.
I have measured with few thousand lines.
The bottleneck could also be ReadAllLines if your text has too many lines. Even though I can't figure out why you would be inserting so many lines, will user be able to find the line he/she needs?
EDIT OK then I suggest you to use BackgroundWorker, here is the code:
First you initialize BackGroundWorker:
BackgroundWorker bgw;
public Form1()
{
InitializeComponent();
bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
}
Then you call it in your method:
private void button1_Click(object sender, EventArgs e)
{
if (!bgw.IsBusy)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Text Files|*.txt";
openFileDialog1.Title = "Select a Text file";
openFileDialog1.FileName = "";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
string file = openFileDialog1.FileName;
listView1.BeginUpdate();
bgw.RunWorkerAsync(file);
}
}
else
MessageBox.Show("File reading at the moment, try later!");
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
listView1.EndUpdate();
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
string fileName = (string)e.Argument;
TextReader t = new StreamReader(fileName);
string line = string.Empty;
while ((line = t.ReadLine()) != null)
{
string nLine = line;
this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(nLine); });
}
}
It will add each line when it reads it, you will have responsive UI, and lines won't affect the listBox before it finishes loading.
It maybe simply not completing its job, and you should have to wait for more. Try with this solution:
http://www.bytechaser.com/en/articles/f3a3niqyb7/display-large-lists-in-listview-control-quickly.aspx
could use a stream to store the data:
class Test
{
public static void Main()
{
string path = #"c:\temp\MyTest.txt";
//Create the file.
using (FileStream fs = File.Create(path))
{
AddText(fs, "This is some text");
AddText(fs, "This is some more text,");
AddText(fs, "\r\nand this is on a new line");
AddText(fs, "\r\n\r\nThe following is a subset of characters:\r\n");
for (int i=1;i < 120;i++)
{
AddText(fs, Convert.ToChar(i).ToString());
}
}
//Open the stream and read it back.
using (FileStream fs = File.OpenRead(path))
{
byte[] b = new byte[1024];
UTF8Encoding temp = new UTF8Encoding(true);
while (fs.Read(b,0,b.Length) > 0)
{
Console.WriteLine(temp.GetString(b));
}
}
}
private static void AddText(FileStream fs, string value)
{
byte[] info = new UTF8Encoding(true).GetBytes(value);
fs.Write(info, 0, info.Length);
}
}
then you event handler
privateasyncvoid Button_Click(object sender, RoutedEventArgs e)
{
UnicodeEncoding uniencoding = new UnicodeEncoding();
string filename = #"c:\Users\exampleuser\Documents\userinputlog.txt";
byte[] result = uniencoding.GetBytes(UserInput.Text);
using (FileStream SourceStream = File.Open(filename, FileMode.OpenOrCreate))
{
SourceStream.Seek(0, SeekOrigin.End);
await SourceStream.WriteAsync(result, 0, result.Length);
}
}
Your application becomes unresponsive because it's waiting for the ReadAllLines method to complete and blocks the UI thread. You may want to read files on a separate thread to avoid blocking the UI. I cannot guarantee that the code below will work without errors but it should give you an idea on how to tackle the problem.
First of all, you'll need a method to append an item to the ListBox:
private void AddListBoxItem(string item)
{
if(!InvokeRequired)
{
listBox2.Items.Add(item);
}
else
{
var callback = new Action<string>(AddListBoxItem);
Invoke(callback, new object[]{item});
}
}
The method above checks if it is executed on UI thread and if yes, it simply adds an item to the listBox2.Items collection; if not, it creates a delegate from itself and invokes that delegate on UI thread.
Next, you'll need to move the code that reads the file to another thread and call AddListBoxItem method. For the sake of readability, let's put that into a separate method:
private void AddFileContentsToList(string fileName)
{
using(var reader = new System.IO.StreamReader(fileName))
{
while(!reader.EndOfStream)
{
var line = reader.ReadLine();
AddListBoxItem(line);
}
}
}
And now we will call the method on a separate thread:
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "Text Files|*.txt";
openFileDialog1.Title = "Select a Text file";
openFileDialog1.FileName = "";
DialogResult result = openFileDialog1.ShowDialog();
if (result == DialogResult.OK)
{
var thread = new Thread(AddFileContentsToList);
thread.Start();
}
Hope this helps!

Categories

Resources