1

I'm a newbie to threading, and I don't really know how to code a particular task. I would like to handle a mouse click event on a window that will kick off a while loop in a seperate thread. This thread, which is distinct from the UI thread, should call a function in the while loop which updates a label on the window being serviced by the UI thread. The while loop should stop running when the left mouse button is no longer being pressed. All the loop does is increment a counter, and then repeatedly call the function which displays the updated value in the window. The code for the window and all of the threading is given below (I keep getting some error about STA threading, but don't know where to put the attribute). Also, I'm hoping to use this solution, if it ever works, in another project that makes asynchronous calls elsewhere to a service via wcf, so I was hoping not to make any application-wide special configurations, since I'm really new to multi-threading and am quite worried about breaking other code in a larger program... Here's what I have:

<Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication2" Name="MyMainWindow" Title="MainWindow" Width="200" Height="150" PreviewMouseLeftButtonDown="MyMainWindow_PreviewMouseLeftButtonDown"> <Label Height="28" Name="CounterLbl" /> </Window> 

And here's the code-behind:

using System.Windows; using System.Windows.Input; using System.Threading; namespace WpfApplication2 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private int counter = 0; public MainWindow() { InitializeComponent(); } private delegate void EmptyDelegate(); private void MyMainWindow_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Thread counterThread = new Thread(new ThreadStart(MyThread)); counterThread.Start(); } private void MyThread() { while (Mouse.LeftButton == MouseButtonState.Pressed) { counter++; Dispatcher.Invoke(new EmptyDelegate(UpdateLabelContents), null); } } private void UpdateLabelContents() { CounterLbl.Content = counter.ToString(); } } } 

Anyways, multi-threading is really new to me, and I don't have any experience implementing it, so any thoughts or suggestions are welcome!

Thanks,

Andrew

Edit:

Here's another version (I also added a grid) using a BackgroundWorker which still complains that the calling thread must be STA...

<Window x:Class="WpfApplication2.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Name="MyMainWindow" Width="200" Height="150" PreviewMouseLeftButtonDown="MyMainWindow_PreviewMouseLeftButtonDown"> <Grid> <Label Height="28" Name="CounterLbl" /> </Grid> </Window> 

and the code behind...

using System.Windows; using System.Windows.Input; using System.Threading; using System.ComponentModel; namespace WpfApplication2 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class Window1 : Window { private int counter = 0; public Window1() { InitializeComponent(); } private delegate void EmptyDelegate(); private void MyMainWindow_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += new DoWorkEventHandler(MyThread); bw.RunWorkerAsync(this); } private void MyThread(object sender, DoWorkEventArgs e) { Window window = e.Argument as Window; while (Mouse.LeftButton == MouseButtonState.Pressed) { counter++; window.Dispatcher.Invoke(new EmptyDelegate(UpdateLabelContents), null); } } private void UpdateLabelContents() { CounterLbl.Content = counter.ToString(); } } } 

1 Answer 1

2

For simplicity, use a BackgroundWorker

This SO answer: Is this thread/background worker design for a C# WPF application OK? has other recommendations, although in your case the BackgroundWorker would seem to fit well, particularly because of the ProgressChanged requirement.

Sign up to request clarification or add additional context in comments.

6 Comments

@Mitch: Thanks Mitch! I'm looking into your suggestions - they seem really promising. I'm going to try to alter the code to use BackgroundWorker, which seems like it might work. I'll post back as soon as I try it out!
@Mitch: Okay, I've tried using BackgroundWorker, but I seem to be running into the same problem concerning STAThread. Not really sure what the best solution for this is. I'll post the BackgroundWorker version in an "Edit" to the original question...
@Andrew: are you hooking up the ProgressChanged event handler, and only using that and the Completed handler to update the UI?
@Mitch: Uh... actually, I was attempting to pass a reference to the Window as a parameter to the worker method. This way, I thought it would be possible to call a method to update the UI via the dispatcher of the window from the worker method... (And then do it again and again in a loop, since the worker method will still be running...)
The ProgressChanged and Completed event handlers, marshall onto the UI for you...
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.