2015-10-06 107 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