开发者

Multi-Threading Question Concerning WPF

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开发者_StackOverflow) 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();
        }
    }
}


For simplicity, use a BackgroundWorker

  • How to: Use a Background Worker

  • Joe Albahari's Threading Tutorial: 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜