2010-12-30 3 views
1

Я новичок в потоковом режиме, и я действительно не знаю, как закодировать конкретную задачу. Я хотел бы обработать событие щелчка мыши в окне, которое начнет цикл while в отдельном потоке. Этот поток, отличный от потока пользовательского интерфейса, должен вызывать функцию в цикле while, которая обновляет метку в окне, обслуживаемом потоком пользовательского интерфейса. Цикл while должен прекратиться, если левая кнопка мыши больше не нажата. Весь цикл выполняет инкремент счетчика, а затем повторно вызывает функцию, которая отображает обновленное значение в окне. Код для окна и все потоки приведены ниже (я продолжаю получать некоторую ошибку о потоке STA, но не знаю, куда поместить атрибут). Кроме того, я надеюсь использовать это решение, если оно когда-либо работает, в другом проекте, который делает асинхронные вызовы в другом месте для службы через wcf, поэтому я надеялся не создавать какие-либо специальные конфигурации приложения, так как я действительно новый многопоточности и я очень беспокоюсь о нарушении другого кода в большей программе ... Вот что у меня есть:Многопоточный вопрос о WPF

<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> 

а вот код-за:

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(); 
     } 
    } 
} 

в любом случае, многопоточность для меня это действительно ново, и у меня нет опыта его реализации, поэтому любые мысли или предложения приветствуются!

Спасибо,

Эндрю

Edit:

Вот другая версия (я также добавил сетку), используя BackgroundWorker, который до сих пор жалуется, что вызывающий поток должен быть 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> 

и код позади ...

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(); 
     } 
    } 
} 

ответ

2

Для простоты, используйте BackgroundWorker

Этот SO ответ: Is this thread/background worker design for a C# WPF application OK? есть другие рекомендации, хотя в вашем случае BackgroundWorker казалось бы, хорошо вписывается, особенно использование требования ProgressChanged.

+0

@Mitch: Спасибо Mitch! Я изучаю ваши предложения - они кажутся действительно многообещающими. Я попытаюсь изменить код для использования BackgroundWorker, который, похоже, может работать. Я отправлю сообщение, как только попробую! – Andrew

+0

@Mitch: Хорошо, я пробовал использовать BackgroundWorker, но, похоже, у меня проблема с STAThread. Не совсем уверен, какое лучшее решение для этого. Я отправлю версию BackgroundWorker в «Редактирование» в исходный вопрос ... – Andrew

+0

@Andrew: вы подключаете обработчик событий ProgressChanged и используете только это и обработчик Completed для обновления пользовательского интерфейса? –

Смежные вопросы