2011-09-26 57 views
1

如何在單擊新按鈕時殺死一個按鈕的事件。單擊新按鈕時殺死一個按鈕事件

我有一個事件(按鈕G)正在運行(有一個while循環等待一些輸入)。 我有另一個退出操作按鈕。 現在。 G按鈕的事件正在運行時,我無法點擊任何其他按鈕。 我該如何解決這個問題? 謝謝

嗨,@Grokodile謝謝你的代碼。所以我在這裏評論你的代碼,我應該把我的工作邏輯代碼放在我下面評論的地方嗎? Thans

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows; 
using System.Windows.Threading; 

namespace WpfApplication1 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private BackgroundWorker _worker; 

     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void RunButtonClickHandler(object sender, RoutedEventArgs e) 
     { 
      _worker = new BackgroundWorker {WorkerSupportsCancellation = true}; 
      _worker.DoWork += BackgroundWorkerTask; 
      _worker.RunWorkerAsync(); 
       //I should Put my job logic here, right? 
     } 

     private void StopButtonClickHandler(object sender, RoutedEventArgs e) 
     { 
      if (_worker != null && _worker.IsBusy) _worker.CancelAsync(); 
      //I should Put my job logic here, right? 

     } 

     private void BackgroundWorkerTask(object sender, DoWorkEventArgs e) 
     { 
      // this runs on the BackgroundWorker thread. 

      while (_worker.CancellationPending == false) 
      { 
       Thread.Sleep(500); 
       // You have to use the Dispatcher to transfer the effects of 
       // work done in the worker thread back onto the UI thread. 
       Dispatcher.BeginInvoke(new Action(UpdateTime), DispatcherPriority.Normal, null); 
      } 
     } 

     private void UpdateTime() 
     { 
      // Dispatcher runs this on the UI thread. 

      timeTextBlock.Text = DateTime.Now.ToString(); 
     } 
    } 
} 
+0

不,您應該將自己的'作業邏輯'放在BackgroundWorkerTask或UpdateTime中,只需使用XXXButtonClickHandler方法來啓動和停止執行,請參閱我的編輯 – Grokodile

回答

3

進一步向H.B.和dowhilefor說,這裏是顯示了啓動使用BackgroundWorker的一個按鈕,並用另一個按鈕結束它在後臺線程任務的樣本,請注意使用Dispatcher.BeginInvoke的:

XAML

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" 
     Height="80" 
     Width="640" 
     FontSize="16"> 
    <DockPanel VerticalAlignment="Center"> 
     <Button Margin="10,0" 
       x:Name="runButton" 
       DockPanel.Dock="Left" 
       Click="RunButtonClickHandler">Run</Button> 
     <Button Margin="10,0" 
       x:Name="stopButton" 
       DockPanel.Dock="Left" 
       Click="StopButtonClickHandler">Stop</Button> 
     <TextBlock Margin="10,0">The Time Is Now:</TextBlock> 
     <TextBlock x:Name="timeTextBlock" 
        Margin="10,0" /> 
    </DockPanel> 
</Window> 

代碼隱藏

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows; 
using System.Windows.Threading; 

namespace WpfApplication1 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private BackgroundWorker _worker; 

     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void RunButtonClickHandler(object sender, RoutedEventArgs e) 
     { 
      _worker = new BackgroundWorker {WorkerSupportsCancellation = true}; 
      _worker.DoWork += BackgroundWorkerTask; 
      _worker.RunWorkerAsync(); 
     } 

     private void StopButtonClickHandler(object sender, RoutedEventArgs e) 
     { 
      if (_worker != null && _worker.IsBusy) _worker.CancelAsync(); 
     } 

     private void BackgroundWorkerTask(object sender, DoWorkEventArgs e) 
     { 
      // this runs on the BackgroundWorker thread. 

      while (_worker.CancellationPending == false) 
      { 
       Thread.Sleep(500); 
       // You have to use the Dispatcher to transfer the effects of 
       // work done in the worker thread back onto the UI thread. 
       Dispatcher.BeginInvoke(new Action(UpdateTime), DispatcherPriority.Normal, null); 
      } 
     } 

     private void UpdateTime() 
     { 
      // Dispatcher runs this on the UI thread. 

      timeTextBlock.Text = DateTime.Now.ToString(); 
     } 
    } 
} 

編輯 - 多一點解釋

RunButtonClickHandler

創建和初始化BackgroundWorker使其支持取消。
DoWorkEventHandler附加到DoWork事件,即BackgroundWorkerTask
通過調用RunWorkerAsync開始執行後臺操作,即創建一個新線程(實際上它使用線程池中的線程)並在該線程上運行BackgroundWorkerTask中的代碼。

BackgroundWorkerTask

如果你想這樣做,否則會導致UI凍結在主UI線程上運行時的工作(例如未發現的素數),那麼你在後臺線程在這裏做到這一點。

錄入

所有WPF Control期從DispatcherObject繼承,並與管理工作在UI的單一線程中完成執行一個Dispatcher相關。如果您需要執行諸如設置TextBlock的文本之類的工作,則無法從後臺線程執行此操作,嘗試這樣做會導致拋出異常。當從BackgroundWorkerTask調用Dispatcher.BeginInvoke時,UpdateTime排隊回到UI線程的Dispatcher。通過這種方式,您可以在取消後臺線程執行前獲得後臺完成的工作結果。

StopButtonClickHandler

變化_worker.CancellationPending與呼叫真實CancelAsync導致while循環執行離開BackgroundWorkerTask事件處理程序退出,因此。

總之,您可以在兩個地方工作,不管是在BackgroundWorkerTask還是在UpdateTime,但只能對UpdateTime的UI元素進行更改。

+0

感謝您的代碼。請幫我看看我在我的問題帖子中評論過的代碼。這是放置我的工作邏輯代碼的正確位置嗎?謝謝 –

+0

@Anders,我試着在編輯中多解釋一下,希望有所幫助。 – Grokodile

1

不要做UI線程自旋等待的操作,使用新Thread或例如Timer

1

你不能。 UI在單線程中運行,通常稱爲主線程或ui線程。用你的while循環你會阻塞整個UI線程,因此你不能接收任何進一步的輸入。 我建議你查看BackgroundWorker類,也許可以查看更多有關如何設計線程和後臺任務以在UI環境中正常工作的MSDN文章。