2009-11-02 4 views
6

Ich erstelle meine eigenen FrameworkElement und überschreiben VisualChildrenCount{get;} und GetVisualChild(int index) durch die Rückgabe meiner eigenen DrawingVisual Instanz.DrawingVisual wird nicht aktualisiert

Wenn ich den Inhalt der visuellen nach dem ersten Rendern (z. B. in Timer-Handler) mit DrawingVisual.RenderOpen() ändern und in den Kontext zeichnen, wird das Element nicht aktualisiert.

Hier ist das einfachste Beispiel:

using System; 
using System.Windows; 
using System.Windows.Media; 
using System.Windows.Threading; 

namespace VisualTest 
{ 
    public class TestControl : FrameworkElement 
    { 
     private readonly DrawingVisual _visual = new DrawingVisual(); 

     public TestControl() 
     { 
      Draw(false); 

      var timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 2)}; 
      timer.Tick += (sender, args) => 
           { 
            Draw(true); 
            InvalidateVisual(); 
            timer.Stop(); 
           }; 
      timer.Start(); 
     } 

     protected override Visual GetVisualChild(int index) 
     { 
      return _visual; 
     } 

     protected override int VisualChildrenCount 
     { 
      get { return 1; } 
     } 

     private void Draw(bool second) 
     { 
      DrawingContext ctx = _visual.RenderOpen(); 
      if (!second) 
       ctx.DrawRoundedRectangle(Brushes.Green, null, new Rect(0, 0, 200, 200), 20, 20); 
      else 
       ctx.DrawEllipse(Brushes.Red, null, new Point(100, 100), 100, 100); 
      ctx.Close(); 
     } 
    } 
} 

InvalidateVisual() tut nichts. Wenn Sie jedoch die Größe des Fensters ändern, das das Element enthält, wird es aktualisiert.

Haben Sie Ideen, wie Sie den Inhalt richtig aktualisieren können? Vorzugsweise ohne, die neue Abhängigkeitseigenschaften für mein Element einführt.

Antwort

7

hinzufügen

this.AddVisualChild(_visual); 
this.AddLogicalChild(_visual); 

zu Testcontrol Klasse Konstruktor.

+0

Dieser Code führt dazu, dass der visuelle Speicher verloren geht, da er dem Baum hinzugefügt, aber nie entfernt wird. Ein besserer Code besteht darin, das visuelle Ereignis Loaded hinzuzufügen und es im Ereignis Unloaded zu entfernen - siehe meine Antwort. – splintor

5

Basierend auf SMART_n's answer, hier ist eine verbesserte Lösung, die nicht Speicher entweicht:

public TestControl() 
    { 
     Loaded += AddVisualToTree; 
     Unloaded += RemoveVisualFromTree; 

     Draw(false); 

     var timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 2)}; 
     timer.Tick += (sender, args) => 
          { 
           Draw(true); 
           InvalidateVisual(); 
           timer.Stop(); 
          }; 
     timer.Start(); 

    } 

    private void AddVisualToTree(object sender, RoutedEventArgs e) 
    { 
     AddVisualChild(_visual); 
     AddLogicalChild(_visual); 
    } 

    private void RemoveVisualFromTree(object sender, RoutedEventArgs e) 
    { 
     RemoveLogicalChild(_visual); 
     RemoveVisualChild(_visual); 
    } 
0

Wenn Sie _visual eine DrawingGroup machen, können Sie wieder zu öffnen, es später, und ändern Sie es Befehle Zeichnung, und sie werden bleibe auf dem Laufenden.