2013-02-19 67 views
2

您好,我無法理解的問題,我有帆布動畫 - 中環不工作

private void StartReplay(object sender, RoutedEventArgs e) 
    { 
     for (int i = 0; i <= 40; i++) 
     { 
      if (leftCounter < 20) 
      { 
       leftCounter++; 
       leftCounter2 = leftCounter; 
       Canvas.SetLeft(Kwadracik, leftCounter); 
      } 
      else 
      { 
       leftCounter2--; 

       Canvas.SetLeft(Kwadracik, leftCounter2); 
      } 
     } 
    } 

現在2種方式

1)如果我刪除環比每次我會時間單擊一個按鈕,leftCounter將被加1,畫布將被移動。 20的權利比左側多點擊我會做。它按預期工作。第一個在右邊,而不是在左邊

2)當我用循環運行它時,當我點擊按鈕時循環就會結束。但它不會像我預計的那樣工作。我預計它會向右走20,向左走20(20 + 20 = 40)。但不是。它不是在兩邊移動。它只是站着,因爲它跳到了最後。我看不到右邊的舉動。即使我在每個循環步驟中都會得到小的延遲,GUI仍然凍結,並且在循環結束後解凍,並且元素位於它的位置

爲什麼會有這種差異?我怎樣才能繞過它?這是站在背後

<Canvas x:Name="canvas" HorizontalAlignment="Center" VerticalAlignment="Center"> 
     <Rectangle Name="Kwadracik" Width="20" Height="20" Canvas.Left="0" Canvas.Top="0" Fill="Blue" /> 
    </Canvas> 

回答

2

XAML是因爲你很可能從GUI線程中調用StartReplay。線程處理僅在您的功能完成後繼續。換句話說,在你的函數完成之前,GUI不能處理你的修改。當你在也是gui線程的按鈕點擊處理程序中進行更改時,將退出你的功能,然後gui反映更改。這就是爲什麼第一種方法是通過點擊來工作。

你可以做的是啓動工作線程並在那裏進行修改,或者因爲這看起來像動畫般的行爲,所以使用計時器。

更新: 實施例1:

DispatcherTimer在調用線程執行回調。

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Threading; 


namespace CanvasAnimation 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     DispatcherTimer uiTimer; 
     double directionDelta = 1.0; 

     public MainWindow() 
     { 
      InitializeComponent(); 
      uiTimer = new DispatcherTimer(); //This timer is created on GUI thread. 
      uiTimer.Tick += new EventHandler(uiTimerTick); 
      uiTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000/25); // 25 ticks per second 
      uiTimer.Start(); 
     } 

     private void uiTimerTick(object sender, EventArgs e) 
     { 
      double currentLeft = Canvas.GetLeft(Kwadracik); 

      if (currentLeft < 0) 
      { 
       directionDelta = 1.0; 
      } 
      else if (currentLeft > 80) 
      { 
       directionDelta = -1.0; 
      } 

      currentLeft += directionDelta; 

      Canvas.SetLeft(Kwadracik, currentLeft); 
     } 
    } 
} 

實施例2:使用簡單定時器

using System; 
using System.Threading; 
using System.Windows; 
using System.Windows.Controls; 

namespace CanvasAnimation 
{ 
    /// <summary> 
    /// Interaction logic for WorkerTimer.xaml 
    /// </summary> 
    public partial class WorkerTimer : Window 
    { 
     Timer timer; 
     double directionDelta = 1.0; 

     public WorkerTimer() 
     { 
      InitializeComponent(); 
      timer = new Timer(this.timerTick, this, 0, 1000/25); // 25 fPS timer 
     } 

     protected void timerTick(Object stateInfo) 
     { 
      //This is not a GUI thread!!!! 
      //So we need to Invoke delegate with Dispatcher 
      this.Dispatcher.Invoke(new MoveCanvasDelegate(this.moveCanvas), null); 
     } 

     protected delegate void MoveCanvasDelegate(); 
     protected void moveCanvas() 
     { 
      //This function must be called on GUI thread!!! 

      double currentLeft = Canvas.GetLeft(Kwadracik); 

      if (currentLeft < 0) 
      { 
       directionDelta = 1.0; 
      } 
      else if (currentLeft > 80) 
      { 
       directionDelta = -1.0; 
      } 

      currentLeft += directionDelta; 

      Canvas.SetLeft(Kwadracik, currentLeft); 
     } 
    } 
} 

同樣的技術適用於BackgroundWorker的或其他非GUI線程。

+0

是的我從GUI開始它,因爲我正在使用按鈕。好的,你能指出我如何使用計時器來處理這種情況嗎?我這樣做了。我如何啓動工作線程?我想通過'Task.Run'把它交給Task,但我無法更新GUI,因爲我得到異常,該元素由其他線程擁有 – Fixus 2013-02-19 18:17:04

+0

有很好的DispatcherTimer類,它在調用線程上執行回調。我會更新答案 – 2013-02-19 19:05:39