2015-10-06 3 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# -код:

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? Более конкретно, какой поток? Если вы используете симуляцию в потоке пользовательского интерфейса, холст не будет обновляться до тех пор, пока это не будет завершено. Обычно рекомендуется использовать класс Dispatcher, вызывая либо Invoke, либо BeginInvoke.

Как я уже сказал, я не знаю, где вы совершаете звонок из, но рендер может выглядеть следующим образом:

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

This, кажется, еще один хороший (хотя и старый) вопрос для обновления графического интерфейса пользователя из другого потока.

Если вы посмотрите на свой вопрос, вы должны перенести свой код обновления в другой поток. Прохождение всех итераций в конструкторе, как и сейчас, безусловно, блокирует все остальное. В основном все, после InitializeComponent(), должно быть обработано с помощью обратного вызова или потока.

+0

Я назвал '' element.InvalidateVisual' за Canvas.SetLeft (ANT1, муравьи [0] .Position.X); '. Теперь я создам новый поток. – kame

Смежные вопросы