2016-09-27 83 views
1

我有一個矩形,我想使其可見,然後我想等待500毫秒,然後我想再次使它不可見。如何使用BackgroundWorker來顯示/隱藏WPF UI元素?

起初我試過這段代碼:

MuzzleFlash.Visibility = Visibility.Visible; 
Thread.Sleep(500); 
this.UpdateLayout(); 
this.InvalidateVisual(); 
MuzzleFlash.Visibility = Visibility.Collapsed; 

我想這兩個中間線作爲他們理應被迫窗戶更新,但是這一切確實是半秒鐘的停頓不改變任何形式的矩形。

所以我聽說了BackgroundWorkers以及他們應該如何使用。經過一番簡短的閱讀後,我想出了這個。需要注意的是拍攝被預訂在畫布MouseDown事件,這在以前的工作:

private void Shoot(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 

     BackgroundWorker UIUpdater = new BackgroundWorker(); 
     UIUpdater.WorkerSupportsCancellation = true; 
     UIUpdater.WorkerReportsProgress = false; 

     UIUpdater.DoWork += new DoWorkEventHandler(UI_DoWork); 
     UIUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler(cancelUIUpdate); 

    } 

    private void UI_DoWork(object sender, DoWorkEventArgs e) 
    { 
     MuzzleFlash.Visibility = Visibility.Visible; 
     Thread.Sleep(500); 
     this.UpdateLayout(); 
     this.InvalidateVisual(); 
     MuzzleFlash.Visibility = Visibility.Collapsed; 
    } 

    private void cancelUIUpdate(object sender, RunWorkerCompletedEventArgs e) 
    { 
     BackgroundWorker bw = sender as BackgroundWorker; 
     bw.CancelAsync(); 
    } 

現在它甚至不停頓半秒,這表明,我認爲工人沒有做任何事情。我該如何解決這個問題,並使矩形出現/消失?

+2

我會使用一個計時器。你並沒有真的在做工作。 – Paparazzi

+0

它不起作用,因爲您正在執行工作線程中的所有操作。主UI線程說*「啓動一個後臺工作,然後結束」*,而bg工人說*「設置可見標誌爲真,等待一段時間,設置可見標誌爲假,然後結束回UI線程,以便UI可以更新」*。請注意,bg線程永遠不會將通知發送回主UI線程以更新顯示。如果你想這樣做,我會建議尋找WPF的Dispatcher。請參閱[本答案](http://stackoverflow.com/a/15930792/302677)以獲得一個簡短摘要,其中使用了與您在此處執行的操作類似的示例。 – Rachel

+1

一個簡單的「解決方案」就是將你的'MuzzleFlash.Visibility = Visibility.Visible'行移動到你的主UI線程以在'Shoot(...)'方法內執行。然後代碼表示*「設置可見標誌爲真,啓動bg工作,然後結束並更新顯示」*,而bg工人說*「等待一段時間,設置可見標誌爲假,然後結束回UI線程,以便它可以更新」* 。此外,您可能希望在RunWorkerCompleted中放置*「set visible flag false」*位,因爲WPF通常不會更新它們未創建的線程上的對象,因此您可能會遇到嘗試從bg更新的異常工人。 – Rachel

回答

4

這是壞主意,使用後臺工作在WPF管理動畫後設置的值。動畫應該從Storyboard運行。它可以通過xaml或代碼來指定。

你的動畫矩形的問題是非常簡單的使用XAML:

<Rectangle x:Name="MuzzleFlash" Height="100" Width="100" Fill="Red"> 
    <Rectangle.Triggers> 
     <EventTrigger RoutedEvent="Loaded"> 
      <BeginStoryboard> 
       <Storyboard> 
        <ObjectAnimationUsingKeyFrames BeginTime="0:0:0.5" Storyboard.TargetProperty="Visibility"> 
         <DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" /> 
        </ObjectAnimationUsingKeyFrames> 
       </Storyboard> 
      </BeginStoryboard> 
     </EventTrigger> 
    </Rectangle.Triggers> 
</Rectangle> 

對於更復雜的動畫,可以使用混合交互設計它們。

評論後更新的回覆: 如果您想要顯示並消失,您必須從父容器中操作它,因爲一旦矩形隱藏,它將不響應鼠標事件。

您可以將矩形放入網格中並通過名稱引用它以更改其在動畫中的可見性。

<Grid Background="Gray"> 
    <Grid.Triggers> 
     <EventTrigger RoutedEvent="MouseDown"> 
      <BeginStoryboard> 
       <Storyboard> 
        <ObjectAnimationUsingKeyFrames BeginTime="0:0:0.0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="MuzzleFlash"> 
         <DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" /> 
         <DiscreteObjectKeyFrame KeyTime="0:0:0.5" Value="{x:Static Visibility.Hidden}" /> 
        </ObjectAnimationUsingKeyFrames> 
       </Storyboard> 
      </BeginStoryboard> 
     </EventTrigger> 
    </Grid.Triggers> 
    <Rectangle x:Name="MuzzleFlash" Height="100" Width="100" Fill="Red"> 

    </Rectangle> 
</Grid> 
+0

那我該如何觸發呢?從字面上加載只是意味着'加載'還是我可以從代碼中調用它? – lordnoob

+0

你想如何觸發它?這裏的例子使用Loaded就是一個例子。您可以爲任何事件觸發它。爲什麼你認爲你需要它從代碼觸發它? – loopedcode

+0

好吧,我基本上想要它,所以當我點擊矩形顯示半秒鐘,然後再次消失。我將事件設置爲MouseDown,默認情況下將可見性設置爲隱藏(因此x:靜態可見性在故事板中可見),但它不起作用(無響應)。我認爲我之前得到了一些迴應,當我把它作爲MouseDown時,默認情況下是可見的,因此隱藏。 – lordnoob

0
private BackgroundWorker bw = new BackgroundWorker(); 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     //Background Worker code/// 
     bw.WorkerReportsProgress = true; 
     bw.DoWork += bw_DoWork; 
     bw.ProgressChanged += bw_ProgressChanged; 
     bw.RunWorkerCompleted += bw_RunWorkerCompleted; 
     bw.RunWorkerAsync(); 

     //Progress Bar Window 
     grdProgress.Visibility = Visibility.Visible; 
    } 
    private void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     //something to do 
    } 

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     //Progress Bar Window close 
     grdProgress.Visibility = Visibility.Hidden; 
    } 

    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     prg.Value = e.ProgressPercentage; 
    } 


    bw.ReportProgress(value); 
+0

除了提供代碼,請解釋爲什麼你的答案有效。 – buczek