Whats wrong with my backgroundwork method - wpf

I am trying to get a background worker process working in a wpf application. it creates 2 files then crashes.
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
CreateFile(i.ToString());
};
worker.RunWorkerAsync();
private void CreateFile(string fileName)
{
string path = string.Format(#"{0}\{1}.txt", directory, fileName);
using (StreamWriter sw = new StreamWriter(path))
{
sw.WriteLine(fileName);
}
}
I get this error "
The requested operation cannot be performed on a file with a user-mapped section open." what am I doing wrong?
Any help would be great

Another process has the file open, e.g., an antivirus program or WordPad. You can use Process Monitor to see which process it is.

Related

Application Level Unhandled Exceptions Not Creating New File

I have a bit of code in my App.cs file to catch unhandled exceptions in the event of a crash. The problems is when I step through the code, it reads as if the file exists, but no new file is actually created. I am probably overlooking something simple but I could use a second (or more ;)) set of eyes on it. Here is my method.
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
var contents =
string.Format(
"HResult: {1}{0}" + "HelpLink: {2}{0}" + "Message: {3}{0}" + "Source: {4}{0}"
+ "StackTrace: {5}{0}" + "{0}",
Environment.NewLine,
e.Exception.HResult,
e.Exception.HelpLink,
e.Exception.Message,
e.Exception.Source,
e.Exception.StackTrace);
if (!File.Exists("/Source/CrashLogs/Exceptions.txt"))
{
File.WriteAllText("/Source/CrashLogs/Exceptions.txt", contents);
}
else
{
File.AppendAllText("/Source/CrashLogs/Exceptions.txt", contents);
}
e.Handled = true;
}
I'll next expand this out so that the file name contains the current date, but I would just like to get it running first.
Thanks!!
is folder /Source/CrashLogs/ already exists?
handle also AppDomain.CurrentDomain.UnhandledException
more info here

WPF application + command line arguments

I am trying to process command line arguments for my WPF application for this I have made following changes
I have converted the output type as - Console Application
commented the StartupUri parameter in App.xaml
and override the
protected override void OnStartup(StartupEventArgs e)
{ }
Here is my overridden method
public partial class App : Application
{
[DllImport("Kernel32.dll")]
public static extern bool AttachConsole(int processId);
[DllImport("Kernel32.dll")]
public static extern bool FreeConsole();
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
if (e.Args != null && e.Args.Length > 0)
{
ExecutionMethod.CommandLine = true;
ProcessCommandLineArgs.ProcessArgs(e.Args);
base.Shutdown();
}
else
{
FreeConsole();
ExecutionMethod.CommandLine = false;
TestApp WindowToDisplay = new TestApp();
WindowToDisplay.Show();
}
}
}
I am able to process the arguments and display the result on console.
But the issues is
This TestApp, creates process, say P1 , which execute some commands and result gets re-directed to console output.
Before P1 completes, main process exited due to base.Shutdown() in above overridden method.
How I can make this base.shutdown to wait for Process P1 to finish.
Any link/suggestions
Regards
I was actually waiting for new process, P1, to exit.
I synchronized main process and process P1.
Making ProceedForShutdwon to true only when process P1 gets exited
while (ExecutionMethod.ProceedForShutDown == false)
{
mut.WaitOne(500); // wait for 500 ms
}
base.Shutdown();
I am able to achieve my goal.
Hope this will help others also.

run multiple tasks in parallel using C#.net 2.0

I need to perform 2 tasks in parallel. One will load data in the GUI, till then I want to run a progress bar continuously in front of user. I tried BackgroundWorker but it is giving me some Thread synchronization error. Can somebody suggest me any other best way of doing same.
Code:
backgroundWorker1 initialization:
backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
if (backgroundWorker1.IsBusy != true)
{
backgroundWorker1.RunWorkerAsync();
}
error coming on following line:
XmlDocumentHierarchy _remoteObj = new XmlDocumentHierarchy(comboBox2.Text, "username", "password");
is:
"Cross-thread operation not valid: Control 'comboBox2' accessed from a thread other than the thread it was created on."
You are trying access comboBox2.Text in thread other than GUI thread (background worker thread). If you using only one property in background worker thread, than you can pass `comboBox2.Text' to background worker method:
if (backgroundWorker1.IsBusy != true)
{
backgroundWorker1.RunWorkerAsync(comboBox2.Text);
}
In backgroundWorker1_DoWork procedure you can read property in following way:
void backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e)
{
String comboBoxText = (String)e.Argument;
XmlDocumentHierarchy _remoteObj = new XmlDocumentHierarchy(comboBoxText, "username", "password");
}
If you accessing more than one property from GUI controls you can create simple class to pass all necessary data to your background worker method.
If you need to access GUI thread from BackgroundWorker thread, you can easily invoke your methods in the GUI thread like this:
public Form1()
{
InitializeComponent();
Thread thr = new Thread(new ThreadStart(BackGroundThread));
thr.Start();
}
void BackGroundThread()
{
for (int i = 0; i < 100; i++)
{
// The line below will be run in the GUI thread with no synchronization issues
BeginInvoke((Action)delegate { this.Text = "Processed " + i.ToString() + "%"; });
Thread.Sleep(200);
}
}

WPF using and accessing an ObjectContext from the BackgroundWorker thread

I have a code like the following (I have stripped some code for readability)
private void RicercaArticoloStripped(object sender, DoWorkEventArgs e)
{
try
{
using (var context = new ControlloSchedeLocalEntities())
{
var prodotti = context.VProdotti.Where(i => i.WACMAT == textBoxCodiceArticolo.Text);
if (prodotti.Count() > 0)
{
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
textBlockDescrizioneArticolo.Text = prodotti.FirstOrDefault().WADESC;
}));
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error:\n\n" + ex.Message + "\r\nStack: " + ex.ToString());
}
}
private void textBoxCodiceArticolo_KeyUpStripped(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += new DoWorkEventHandler(RicercaArticoloStripped);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RicercaArticoloWorkerCompleted);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
object[] parameters = new object[] { textBoxCodiceArticolo.Text, textBlockDescrizioneArticolo.Text };
worker.RunWorkerAsync(parameters);
}
}
So, as for my understanding of BackgroundWorker, when I instantiate the:
var prodotti = context.VProdotti.Where(i => i.WACMAT == textBoxCodiceArticolo.Text);
I am doing it FROM the working thread, not the UI thread.
But I get an exception on the line immediately below, when I try to access the value:
if (prodotti.Count() > 0)
I get the (in)famous error:
"The calling thread cannot access this object because a different thread owns it"
Why?
As you already said you must use Dispatcher.BeginInvoke/Invoke to perform operations from the control's owner thread or you will get "The calling thread cannot access this object because a different thread owns it" exception. Thats why you got this exception;
And here is why you got this exception on the line below (when prodotti.Count() was called):
When you create prodotti variable it's just a IEnumerable<T> object. So he actually calculates only when you call for prodotti.Count() method and thats why you got exception on this line.
IEnumerable actually is generator, that means that he will produce new set of objects every time he used.
To test this you can calculate prodotti as shown bellow:
var prodotti = context.VProdotti.Where(i => i.WACMAT == textBoxCodiceArticolo.Text).ToList();
In this case you will get exception immediately because .ToList() forces all calculations.
Check this article for generators and enumerators: http://www.codeproject.com/Articles/155462/IEnumerable-Lazy-and-Dangerous
Updated:
really, when you use IEnumerable with reference types you can get the same objects as previously. Read this answer for more: https://stackoverflow.com/a/14361094/1467309
The property Text of TextBox gets the value of the DependencyProperty Text, this can only be done from the UI-thread. You are accessing textBoxCodiceArticolo.Text from your Worker thread.

OpenNetCF FTP class multithreading question

Currently, I have something like:
public partial class Form1 : Form
{
delegate void StringDelegate(string value);
private FTP m_ftp;
public Form1()
{
InitializeComponent();
}
private void connect_Click(object sender, EventArgs e)
{
OnResponse("Connecting");
m_ftp = new FTP(server.Text);
m_ftp.ResponseReceived += new FTPResponseHandler(m_ftp_ResponseReceived);
m_ftp.Connected += new FTPConnectedHandler(m_ftp_Connected);
m_ftp.BeginConnect(user.Text, password.Text);
}
void m_ftp_Connected(FTP source)
{
// when this happens we're ready to send command
OnResponse("Connected.");
}
void m_ftp_ResponseReceived(FTP source, FTPResponse Response)
{
OnResponse(Response.Text);
}
private void OnResponse(string response)
{
if (this.InvokeRequired)
{
this.Invoke(new StringDelegate(OnResponse), new object[] { response } );
return;
}
}
private void getFileList_Click(object sender, EventArgs e)
{
FTPFiles files = m_ftp.EnumFiles();
fileList.Items.Clear();
foreach (FTPFile file in files)
{
fileList.Items.Add( new ListViewItem( new string[] { file.Name, file.Size.ToString() } ));
}
tabs.SelectedIndex = 1;
}
private void upload_Click(object sender, EventArgs e)
{
FileStream stream = File.OpenRead("\\My Documents\\My Pictures\\Waterfall.jpg");
m_ftp.SendFile(stream, "waterfall.jpg");
stream.Close();
}
Which works fine - this example was taken from the samples. However, after a recent re-visit I have a question. In this particular case since OnResponse() function doesn't update the UI, it seems to serve no purpose here. I removed it (as well as all the calls to it) and it still works like before. Am I missing something?
After reading up more about multi threading with forms, I came to understand that this mechanism (demonstrated in the code above) is there to make sure the UI is responsive.
So in case when we need to say, update a UI element (such as textbox, label etc) we would have OnResponse implemented as follows:
delegate void StringDelegate(string dummy);
void OnResponse(string dummy)
{
if(!InvokeRequired)
{
button1.Text = dummy;
}
else
Invoke(new StringDelegate(OnResponse),new object[] {enabled});
}
If this function is implemented as:
delegate void StringDelegate(string dummy);
void OnResponse(string dummy)
{
if(InvokeRequired)
{
Invoke(new StringDelegate(OnResponse),new object[] {dummy});
return;
}
}
What's the use to have it at all? Is it absolutely necessary?
And another question: is ftp object running on its own thread here?
The FTP object is definitely running on its own thread. How do I know? This line:
m_ftp.BeginConnect(user.Text, password.Text);
This is an asynchronous method. Once you call this, the FTP component will use a thread from the .NET threadpool to do all of the work. This dedicated thread is the one that is used to "raise" the events. Ultimately a "raised event" is just one or more method calls to all of the delegates added to the event invocation list; it is this dedicated thread spun up by the Begin method that calls these methods. This thread is not the same thread as the thread that runs the UI, hence the need for the Invoke calls.
If you want the FTP component to use the UI thread, you'd use the Connect method instead of the BeginConnect method. This means your events wont work either, nor will your UI respond to interaction - this is completely expected because a thread can only do one thing at a time: it's either servicing the UI, or executing the FTP code. This is why you need a 2nd thread.
Make sense?
-Oisin

Resources