装饰器内的动画(调用OnRender)

7

我正在使用.NET 3.5中的装饰器,在覆盖OnRender方法后可以进行绘制,但我需要重新绘制装饰器以更改其外观。

本质上,我正在寻找一种清除绘图上下文并再次调用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));
    }
}
2个回答

11
你的问题的答案是使用InvalidateVisual来再次调用OnRender函数。
然而,我建议你不要自己在OnRender中进行自定义绘制,而是使用标准样式和可视化树模板来构建该装饰者的实际可视化效果。这也意味着你可以在其中运行标准的XAML动画,包括故事版。
如果你想采用这种方法,在你的装饰器类中需要:
  • 在构造函数中调用base.AddVisualChild()或创建具有你想要在装饰器中展示的可视化元素的自己的可视化元素集合
  • 重写ArrangeOverride(Size size)以便正确排列子元素;
  • 重写VisualChildrenCount以返回装饰器可视化树中的子元素数量;
  • 重写GetCisualChild(int index)以返回特定的子元素。
你可以查看ResizingAdorner MSDN示例了解更多信息。

2
非常重要的是,需要理解WPF与Windows.Forms不同。实际上应该将OnRender()称为AccumulateDrawingObjects(),因为它所做的就是这个。WPF积累了一堆绘图对象,并保留这些对象以便在需要时绘制UI。高效更新UI的魔法在于,您实际上可以在OnRender()之后更改该可视树中的对象。
例如,您可以创建一个DrawingGroup "backingStore",并在OnRender期间将其放入DrawingContext中。然后,每当您想要更改可视化内容时,都可以使用DrawingGroup.Open()将新的绘图命令放入其中,WPF将有效地重新呈现UI的那部分。
它看起来像这样:
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();            
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接