2014-09-26 113 views
0

下面是我的問題的簡短例子。 在功能的開始,我想改變一些視覺參數,例如隱藏窗口,使它變成紅色(「我的例子」),並且在函數結束時,我想把它放回去。 Somethig like mouse wait cursor for long-term function。 Somethig like mouse waiting for cursor for long-term function。當線程忙時WPF重繪窗口

是否有任何優雅的方式來使按鈕紅色之前函數OnButtonClick結束 - 方式以允許窗口消息循環來處理請求背景=紅色並聯方式並立即重繪窗口。

private void OnButtonClick(object sender, RoutedEventArgs e) 
{    
      System.Windows.Media.Brush br = ((Button)sender).Background; 
      ((Button)sender).Background = System.Windows.Media.Brushes.Red; 

      Mouse.OverrideCursor = Cursors.Wait; 
      Function(); //long-term function 
      Mouse.OverrideCursor = Cursors.Arrow; 

      ((Button)sender).Background = br;     
} 
+0

什麼是你的問題? – 2014-09-26 08:35:09

+1

將'Function()'放入另一個線程中,例如使用'backgroundworker' – Bolu 2014-09-26 08:36:25

回答

1

你可以在一個新的線程中運行它,無論是後臺工作或使用任務並行庫(見下文)。

private void OnButtonClick(object sender, RoutedEventArgs e) 
{    
      System.Windows.Media.Brush br = ((Button)sender).Background; 
      ((Button)sender).Background = System.Windows.Media.Brushes.Red; 

      Mouse.OverrideCursor = Cursors.Wait; 

      // Run function in a new thread. 
      Task.Factory.StartNew(() => 
      { 
       Function(); // Long running function. 
      }) 
      .ContinueWith((result) => 
       { 
        // Runs when Function is complete... 
        Mouse.OverrideCursor = Cursors.Arrow; 
        ((Button)sender).Background = br;  
       }); 


} 

如果你使用的是.NET 4.5,你也可以使用Async/Await關鍵字來做到這一點。

+0

謝謝,但是這不正是我正在尋找,或者可能是另一個問題:我不希望用戶點擊另一個按鈕,並與窗口交互。長時間運行的函數並不長,原本我只用等待光標,現在我只想給用戶一個關於繁忙窗口的更好的視覺信息。有了後臺任務,用戶不會覺得很忙。 – user2136076 2014-09-26 09:15:53

+1

您的問題要求運行Function()的「並行」方式。我認爲這個答案很好地回答了這個問題。如果您有不同的問題,請在人們花時間回答後再開始一個新問題,而不是改變這個問題。 – BenjaminPaul 2014-09-26 09:17:59

+2

@ user2136076,那麼你可以嘗試這種擴展方法:[刷新/更新WPF控件](http://geekswithblogs.net/NewThingsILearned/archive/2008/08/25/refresh--update-wpf-controls.aspx) – Bolu 2014-09-26 14:30:32

0

有一個簡單的方法來做到這一點。
XAML:

<Button Command="{Binding TestCommand}" Content="Test" Focusable="False" Background="Green"> 
    <Button.Resources> 
     <Style TargetType="Button"> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding Loading}" Value="true"> 
        <Setter Property="Background" Value="Red"/> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Button.Resources> 
</Button> 

這樣它將設置按鈕背景綠色如果加載=假

的.cs:

public class VM : INotifyPropertyChanged 
{ 
    public bool Loading 
    { 
     get { return _loading; } 
     private set 
     { 
      if (value.Equals(_loading)) return; 
      _loading = value; 
      OnPropertyChanged("Loading"); 
     } 
    } 
    public RelayCommand TestCommand 
    { 
     get { return _testCommand; } 
    } 

    void Test(object parameter) 
    { 
     Dispatcher.CurrentDispatcher.BeginInvoke((Action) (() => Loading = true)); 
     //or if you want to do it with more responsive UI then use 
     Dispatcher.CurrentDispatcher.Invoke((Action) (() => Loading = true)); 
     doSomething(); //this could be replaced with BackgroundWorker DoWork function 
     //or this code could be the DoWork function. 
     Loading = false; 
    } 
} 
+1

優雅的解決方案,但您可能會遇到計時問題。我認爲使用Invoke代替BeginInvoke會更好,以確保它立即運行。 – 2014-11-04 10:55:01

+0

感謝@MarkTravis的建議,我已經更新了我的答案。 – XAMlMAX 2014-11-05 10:35:23

+1

@MarkTravis'Invoke'不能保證立即啓動委託,但它會阻塞調用線程,直到委託被調度線程處理 - 它同步運行。 http://stackoverflow.com/questions/229554/whats-the-difference-between-invoke-and-begininvoke – Gusdor 2014-11-05 10:38:21