2009-11-02 30 views
6

Creo mi propio FrameworkElement y anulo VisualChildrenCount{get;} y GetVisualChild(int index) devolviendo mi propia instancia DrawingVisual.DrawingVisual no se actualiza

Si modifico el contenido de la imagen visual después de la representación inicial (por ejemplo, en el controlador del temporizador) utilizando DrawingVisual.RenderOpen() y dibujo en el contexto, el elemento no se actualiza.

Aquí es la muestra más simple:

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() no hace nada. Aunque si cambia el tamaño de la ventana que contiene el elemento, se actualiza.

¿Alguna idea sobre cómo actualizar correctamente el contenido? Preferentemente sin introduciendo nuevas propiedades de dependencia para mi elemento.

Respuesta

7

Añadir

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

al constructor de la clase TestControl.

+0

Este código provocará que la memoria pierda memoria, ya que se agrega al árbol, pero nunca se elimina. Un mejor código es agregar el visual en el evento Loaded, y eliminarlo en el evento descargado - ver mi respuesta. – splintor

5

Basado en SMART_n's answer, aquí es una solución mejorada que no gotea la memoria:

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

Si haces _visual un DrawingGroup, puede volver a abrirlo más adelante y cambiar su dibujo comandos, y se estar actualizado.

Cuestiones relacionadas