2009-02-24 6 views
6

J'utilise un Adorner dans .NET 3.5, et je suis capable de dessiner en surchargeant OnRender, mais j'ai besoin de la possibilité de redessiner l'adorner pour changer son apparence. Essentiellement, je cherche un moyen d'effacer le contexte de dessin et d'appeler à nouveau OnRender. Quelle est la meilleure façon de le faire, ou y a-t-il une meilleure approche?Animation à l'intérieur d'un adorner (appelant OnRender)

public class MyAdorner : Adorner 
{ 
    private Brush brush = Brushes.Red; 

    public DragArrowAdorner(UIElement adornedElement) : base(adornedElement) 
    {} 

    public void RedrawWithBrush(Brush newBrush) 
    { 
     brush = newBrush; 

     // redraw..? 
    } 

    protected override void OnRender(System.Windows.Media.DrawingContext drawingContext) 
    { 
     // some drawing code... 
     drawingContext.DrawRectangle(
      brush, 
      null, 
      new Rect(AdornedElement.DesiredSize)); 
    } 
} 

Répondre

10

La réponse à votre question est d'utiliser InvalidateVisual pour provoquer l'OnRender à appeler à nouveau

Cependant, je suggère au lieu de faire le dessin personnalisé sur OnRender-vous utiliser le style standard et templating arbre visuel Construire le visuel réel de l'adorner. Cela signifie également que vous pouvez exécuter des animations XAML standard à l'intérieur avec des storyboards.

Si vous voulez aller avec cette approche, dans votre classe Adorner vous devez:

  • dans le constructeur soit appeler base.AddVisualChild() ou créer votre propre collection de visuels avec les visuels que vous souhaitez afficher dans la Adorner
  • déroger ArrangeOverride(Size size) afin d'arranger les enfants correctement;
  • outrepasse VisualChildrenCount pour renvoyer le nombre d'enfants dans l'arborescence visuelle adorner;
  • remplacer GetCisualChild(int index) pour renvoyer un enfant particulier.

Vous pouvez consulter l'exemple MSDN ResizingAdorner pour plus d'informations.

0

Il est très important de comprendre que WPF n'est pas comme Windows.Forms. OnRender() devrait vraiment s'appeler AccumulateDrawingObjects(), parce que c'est ce qu'il fait. WPF accumule un tas d'objets de dessin, qu'il conserve pour pouvoir dessiner l'interface utilisateur chaque fois qu'il le faut. La magie de la mise à jour efficace de l'interface utilisateur est que vous pouvez réellement changer objets dans cet arbre visuel aprèsOnRender().

Par exemple, vous pouvez créer un DrawingGroup "backingStore" et le mettre dans le DrawingContext pendant . Puis, à chaque fois que vous voulez modifier le visuel, vous pouvez ajouter DrawingGroup.Open() de nouvelles commandes de dessin, et WPF restaure efficacement cette partie de l'interface utilisateur.

Il ressemble à ceci:

DrawingGroup backingStore = new DrawingGroup(); 

protected override void OnRender(DrawingContext drawingContext) {  
    base.OnRender(drawingContext);    

    Render(); // put content into our backingStore 
    drawingContext.DrawDrawing(backingStore); 
} 

// I can call this anytime, and it'll update my visual drawing 
// without ever triggering layout or OnRender() 
private void Render() {    
    var drawingContext = backingStore.Open(); 
    Render(drawingContext); 
    drawingContext.Close();    
}