2009-11-02 12 views
6

Tworzę własny FrameworkElement i zastępuję VisualChildrenCount{get;} i GetVisualChild(int index), zwracając moją własną instancję DrawingVisual.RysunekVisual nie jest odświeżany

Jeśli zmodyfikuję zawartość obrazu po wstępnym renderowaniu (np. W programie obsługi czasomierza), używając DrawingVisual.RenderOpen() i rysując do kontekstu, element nie zostanie odświeżony.

Oto najprostszy przykład:

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() nic nie robi. Chociaż zmiana rozmiaru okna zawierającego element zostanie zaktualizowana.

Jakieś pomysły na poprawne odświeżenie zawartości? Korzystnie bez wprowadzenie nowych właściwości zależności dla mojego elementu.

Odpowiedz

7

Dodaj

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

do TestControl klasy konstruktora.

+0

Kod ten spowoduje wyciek pamięci, ponieważ jest dodawany do drzewa, ale nigdy nie został usunięty. Lepszym kodem jest dodanie wizualnego na załadowanym zdarzeniu i usunięcie go na rozładowanym zdarzeniu - zobacz moją odpowiedź. – splintor

5

podstawie SMART_n's answer, tutaj jest ulepszoną rozwiązanie, które nie wyciek pamięci:

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

Jeśli się _visual się DrawingGroup, można ponownie otworzyć go później zmienić jego poleceń rysowania, a oni będą być na bieżąco.