2015-10-06 78 views
2

我想在畫布上顯示移動螞蟻的動畫。因此橢圓的位置應該改變。這些步驟的計算是有效的,但我無法在MainWindow中顯示橢圓位置的變化。只有在完成所有螞蟻步驟的計算後,纔會顯示畫布。更新WPF中的畫布

XAML代碼:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WpfApplication1" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Canvas Name="myCanvas"> 
     <Ellipse x:Name="ant1" Width="11" Height="11" Stroke="Black" Fill="Red"/> 
    </Canvas> 
</Window> 

C#-code:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
using System.Threading; 
using System.Diagnostics; 
using System.Windows.Threading; 

namespace WpfApplication1 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 




      var random = new Random(); 

      var iterations = 10000; 

      var numberOfAnts = 10; 
      var ants = CreateAntCollection(numberOfAnts); 

      // time-loop 
      for (var iteration = 0; iteration < iterations; iteration++) 
      { 

       // move ants 
       foreach (var ant in ants) 
       { 
        var x = (random.Next(3) - 1) + ant.Position.X; 
        var y = (random.Next(3) - 1) + ant.Position.Y; 

        ant.Move(x, y); 
       } 

       // animate the ant 
       // test - todo 
       Debug.WriteLine(ants[0].Position.X); 
       Canvas.SetLeft(ant1, ants[0].Position.X); // movement not shown 
      } 
     } 

     private static List<Ant> CreateAntCollection(int count) 
     { 
      var ants = new List<Ant>(count); 

      for (var i = 0; i < count; i++) 
      { 
       var name = string.Format("ant-{0}", i); 

       var ant = new Ant(name); 

       ants.Add(ant); 
      } 

      return ants; 
     } 

    } 


    class Ant 
    { 
     public Ant(string name) 
     { 
      Name = name; 
      Position = new Position(80, 80); 
     } 

     public string Name { get; private set; } 

     public Position Position { get; private set; } 

     public void Move(int x, int y) 
     { 
      Position = new Position(x, y); 
     } 

     public override string ToString() 
     { 
      return Name; 
     } 
    } 


    struct Position 
    { 
     public readonly int X; 

     public readonly int Y; 

     public Position(int x, int y) 
     { 
      X = x; 
      Y = y; 
     } 

     public override string ToString() 
     { 
      return string.Format("{0},{1}", X, Y); 
     } 
    } 
} 

該 「辦法」 不起作用:element.InvalidateVisual();

回答

2

問題是,您正在同步運行該運動。你需要在另一個線程中執行它。類似這樣的:

Task.Run(() => { 
    for (var iteration = 0; iteration < iterations; iteration++) 
    { 
     // move ants 
     foreach (var ant in ants) 
     { 
      var x = (random.Next(3) - 1) + ant.Position.X; 
      var y = (random.Next(3) - 1) + ant.Position.Y; 
      ant.Move(x, y); 
     } 

     // animate the ant 
     Debug.WriteLine(ants[0].Position.X); 
     this.Dispatcher.Invoke((Action)(() => 
     { 
      Canvas.SetLeft(ant1, ants[0].Position.X); 
     })); 
    } 
}); 
+0

我編輯了源代碼。你可以嗎?這對我有用。 – kame

+0

@ kame是的,新來源更清潔,謝謝! – Domysee

1

從你在哪裏打電話element.InvalidateVisual?更具體地說,哪個線程?如果您在UI線程上運行模擬,畫布將不會更新,直到完成。通常建議通過撥打InvokeBeginInvoke來使用Dispatcher

正如我所說的,我不知道你是從打電話,但渲染可能是這樣的:

private void Render() 
{ 
    Dispatcher.Invoke((Action)(() => 
    { 
     element.InvalidateVisual(); 
    })); 
} 

This似乎是另一個很好的(儘管舊)問題用於更新GUI來自另一個線程。

仔細看看你的問題,你應該將你的更新代碼移動到另一個線程。像現在這樣在構造函數中進行所有迭代,肯定會阻止其他所有內容。基本上,InitializeComponent()之後的所有內容都應該使用回調或線程處理。

+0

我在Canvas.SetLeft(ant1,ants [0] .Position.X)後面調用'element.InvalidateVisual';'。現在我將創建一個新線程。 – kame