Add items to listbox By thread in WPF using C# - wpf

I am using the code below, however it is causing my application to hang and I am unsure as to why. Would anyone be able to help me out here?
void put_items() {
listb.Dispatcher.BeginInvoke(new Action(() =>
{
for (int i = 0; i < 9000000; i++)
{
listb.Items.Add(i.ToString());
}
}));
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread mythread = new Thread(put_items);
mythread.Start();
}

If you want to update any UI controls this has to be done in the UI thread. By using the Dispatcher you force your application to execute the code within BeginInvoke-block to be executed on the ui thread.
Depending on how time consuming the work for one item in the for loop is, you could process a bunch of items (say 10 or 100) and then update the ui by using the dispatcher. Notice that each call of Dispatcher.BeginInvoke needs some time (maybe 500 ms).
Another way would be using an event aggregator see here. Then your class containing the button click method would register to the event aggregator and in the thread you would just need the instance of the aggregator and call ea.Publish(new YourCustomEvent(yourItemToUpdateUI)).
This approach is really nice if your application is going to be complex.

thank you but I think that code not work in netframwork 3.5 I think that I resolve By this code
public void put_items()
{
for (int i = 0; i < 999999999; i++)
{
this.Dispatcher.Invoke(new Action (() =>
{
listb.Items.Add(i.ToString());
}));
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
new Thread(put_items).Start();
}

Related

Modal Messagebox from background thread

I've noticed that there seems to be inconsistent behavior as to when a MessageBox is modal.
First up, launching a MessageBox from the UI thread. This results in a modal MessageBox, as expected :
void MainThreadClick(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello!");
}
Next up, launching from a background thread. This results in a Modeless MessageBox, I assume because it's not on the UI thread?
void WorkerThreadClick(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem((x) =>
{
MessageBox.Show("Hello!");
});
}
Next, launching from a background thread, but dispatched to the UI thread, results in it being modal again :
void WorkerThreadClick(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem((x) =>
{
Application.Current.Dispatcher.Invoke(() =>
{
MessageBox.Show("Hello!");
});
});
}
And finally, this is the strange one, similar to above, but using the FileSystemWatcher thread results in a Modeless dialog. Why is this? ... it's being Invoked on the UI thread, so why isn't it Modal like the previous example?
public MainWindow()
{
InitializeComponent();
m_watcher = new FileSystemWatcher()
{
Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
NotifyFilter = NotifyFilters.LastWrite,
IncludeSubdirectories = true,
Filter = "*.*"
};
m_watcher.Changed += OnFileSystemResourceChanged;
m_watcher.EnableRaisingEvents = true;
}
void OnFileSystemResourceChanged(object _sender, FileSystemEventArgs _args)
{
Application.Current.Dispatcher.Invoke(() =>
{
MessageBox.Show("Hello!");
});
}
Whilst I can solve the last problem using the MessagBox.Show() method that takes a Window owner as a parameter, I want to understand what's going on.
Why is the behavior different in the last 2 examples?
This question has indeed stumped me for some time. On doing some analysis I found that in the last case (FileSystemWatcher) the owner changed(I have not yet figured who has taken over the ownership).
I also found that there is a minor but important difference.
In the scenario number 2
void WorkerThreadClick(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem((x) =>
{
MessageBox.Show("Hello!");
});
}
Even though the behaviour is Modeless when ever I close my MainWindow my application is also shut down.
In the FileSystemWatcher scenario the behaviour is again Modeless but when I close my MainWindow the application is not shut down unless I close the MessageBox(so I know that someone has taken over the ownership. Who has taken it I don't know yet).
EDIT
I changed the Shutdown mode in the last scenario
void OnFileSystemResourceChanged(object sender, FileSystemEventArgs args)
{
Application.Current.Dispatcher.Invoke(() =>
{
Application.Current.ShutdownMode=ShutdownMode.OnMainWindowClose;
MessageBox.Show("Test");
});
}
Even then when I close the MainWindow my Application is not closed unless the MessageBox is closed. I tried finding the owner but then I get null reference exceptions.

Why this Asynchronous example works without Dispatcher nor Control.BeginInvoke?

I was testing an Asynchronous example I wrote in other post, I modified it to show some info in a textbox. what happened next I was not expecting. I don't know why it does not throw an exception when modifying a control from another thread. am I blind or why I don't see it?
here is the example, it works the same for silverlight and WinForms:
int rand=0;
public MainPage()
{
InitializeComponent();
}
public Func<Action<int, int>, Action<int>> DownloadDataInBackground = (callback) =>
{
return (c) =>
{
WebClient client = new WebClient();
Uri uri = new Uri(string.Format("https://www.google.com/search?q={0}", c));
client.DownloadStringCompleted += (s, e2) =>
{
callback(c, e2.Result.Length);
};
client.DownloadStringAsync(uri);
};
};
private void button1_Click(object sender, RoutedEventArgs e)
{
int callid = rand++;
Debug.WriteLine("Executing CallID #{0}", callid);
DownloadDataInBackground((c3, r3) =>this.textBox1.Text+=string.Format("The result for the callid {0} is {1} \n", c3, r3))(callid);
}
Tap the button pretty fast, it wont fail.
your help will be very appreciated.
Edit: added picture showing that windows forms always execute controls modification from the main thread, but, why if it is supposed to be another one?
The actual answer to why your code doesn't fail in the way you expect it to is that the WebClient invokes its events on the UI thread. Hence you aren't modifying your control on a different thread as you seem to imagine you are.

Is there "LoadComplete" such an event in Windows Forms?

I want my windows form to be loaded first, render its children and all. After that load heavy data in it. This is why I am looking for any event which I could use just after form loading is complete.
Any thoughts on this?
I have never found a better solution than Activated; although that is raised every time the form receives focus - so you need to filter out all the times after the first:
bool _firstActivation = true;
void Form1_Activated(object sender, EventArgs e)
{
if (_firstActivation)
{
_firstActivation = false;
OnFirstActivation();
}
}
private void OnFirstActivation()
{
}
Perhaps you're looking for the Form.Shown event. If you're doing a lot of intensive work though, perhaps you should be using a background thread anyway to avoid locking up the UI.
Like MikeP said you want to handle the Form.Shown event just once. So just attach to the even and detach once done.
private void frmMain_Load(object sender, System.EventArgs e)
{
// Do stuff in form load.
Shown += FirstShown;
}
private void FirstShown(object sender, EventArgs eventArgs)
{
Refresh();
// Do something here
// Detach from this event.
Shown -= FirstShown;
}
I do that in a way that I fire a timer with duration of 1, and kill it in the event, and with that method, I know that message loop will be empty and form initialization will be complete when my event comes.
Event is set up from Form_OnLoad() method.

Can I use Monitor.Enter/Exit (c# lock) with WPF without fear of reentrancy bugs?

If I use Monitor.Enter/Exit (through the c# lock syntax) in a WPF application, can the dispatcher cause re-entrance?
In the sample below, presuming OnTextChanged is called when the text in a textbox changes, could the call to _worker.RunWorkerAsync() be called incorrectly?
public class SomeClass
{
private object _locker = new object();
private bool _running = false;
private BackgroundWorker _worker;
public void SomeClass()
{
// initialize worker...
}
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lock (_locker)
_running = false;
}
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
// ... do something time consuming ...
}
private void OnTextChanged()
{
lock(_locker)
{
if (!_running)
{
_worker.RunWorkerAsync();
_running = true;
}
}
}
}
I believe it's possible, but I've not been able to reproduce this. Does WPF somehow prevent the dispatcher from invoking waiting tasks when waiting on monitor?
Not sure what you fear. Both OnTextChanged and RunWorkerCompleted run on the UI thread. It won't be re-entrant, you don't need the lock either. Either method can only start running when the UI thread is idle, pumping the message loop.
While not directly related to your question, you could run into register caching issues if you don't mark _running as volatile.
Actually this isn't strictly true, as you are not using a double-checked lock. I've left the information related to volatile there anyway, for your reference.

WPF Dispatcher.BeginInvoke and UI/Background Threads

I think I need some clarifications regarding WPFs Dispatcher.Invoke and Dispatcher.BeginInvoke usage.
Suppose I have some long running 'work' code like such that is invoked on the press of a button in a simple WPF application:
longWorkTextBox.Text = "Ready For Work!";
Action workAction = delegate
{
Console.WriteLine("Starting Work Action");
int i = int.MaxValue;
while (i > 0)
i--;
Console.WriteLine("Ending Work Action");
longWorkTextBox.Text = "Work Complete";
};
longWorkTextBox.Dispatcher.BeginInvoke(DispatcherPriority.Background, workAction);
This code is locking up my user interface while the workAction is being performed. This is because Dispatcher invokes always run on the UI thread, right?
Assuming this, what is the best practice for configuring my dispatcher to execute the workAction in a separate thread from my UI? I know I can add a BackgroundWorker to my workAction to prevent my UI from locking as such:
longWorkTextBox.Text = "Ready For Work!";
Action workAction = delegate
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
Console.WriteLine("Starting Slow Work");
int i = int.MaxValue;
while (i > 0)
i--;
Console.WriteLine("Ending Work Action");
};
worker.RunWorkerCompleted += delegate
{
longWorkTextBox.Text = "Work Complete";
};
worker.RunWorkerAsync();
};
longWorkTextBox.Dispatcher.BeginInvoke(DispatcherPriority.Background, workAction);
Is there any more elegant ways of doing this besides using the BackgroundWorker? I've always heard that the BackgroundWorker is quirky, so I am curious to know of some alternatives.
I honestly think the BackgroundWorker is the most elegant solution for this. I cannot think of a simpler way to do it.
Me too don't like BackgroundWorker.
A simple alternative can be something like:
using System;
using System.Threading;
using System.Windows;
namespace Sample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
longWorkTextBox.Text = "Ready For Work!";
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
new Thread(Work).Start();
}
void Work()
{
longWorkTextBox.Dispatcher.BeginInvoke((Action)(() => { longWorkTextBox.Text = "Working..."; }));
Console.WriteLine("Starting Work Action");
int i = int.MaxValue;
while (i > 0)
i--;
Console.WriteLine("Ending Work Action");
longWorkTextBox.Dispatcher.BeginInvoke((Action)(() => { longWorkTextBox.Text = "Work Complete"; }));
}
}
}
Easy, not?
Charlie's answer is what you are looking for, really.
However, if it's possible you might look at whether or not you can parcel up your work so that the individual units of work are small and don't affect the UI as much. This would allow you to just use the Dispatcher directly. There is a good example of this on the WPF Threading page: https://msdn.microsoft.com/en-us/library/ms741870%28v=vs.100%29.aspx
As its name indicates it will execute in the Background so you don't need to instantiate it with the Dispatcher. Plus if you want this code to run into a WP7 the BeginInvoke does not get the background parameter.
My recommendation is to create the BackgroundWorker as:
BackgroundWorker worker = new BackgroundWorker;
And then create the handlers for the events:
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork +=new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.ProgressChanged +=new ProgressChangedEventHandler(worker_ProgressChanged);
And finally you call:
bkwkPlayingLoop.RunWorkerAsync();
It is a big temptation to use the Dispatcher from inside the DoWork but instead call worker.ReportProgress() and handle the UI from there. You will otherwise face some inconsistencies with the firing of termination events.
Tasks are easier to use than Background workers, do more things, have fewer issues and were pretty much created so Background Workers didn't need to be used anymore...

Resources