我在.NET 3.5中使用了一个Adorner,我可以通过覆盖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));
}
}
答案 0 :(得分:10)
您的问题的答案是使用InvalidateVisual
来重新调用OnRender
但是,我建议不要自己在OnRender上进行自定义绘图,而是使用标准样式和可视化树模板来构建装饰器的实际视觉效果。这也意味着您可以使用故事板在其中运行标准的XAML动画。
如果你想采用这种方法,在你的装饰课上你需要:
base.AddVisualChild()
或使用要在装饰器中显示的视觉效果创建自己的视觉效果集合ArrangeOverride(Size size)
以便正确安排孩子; VisualChildrenCount
以返回装饰者可视树中的子项数; GetCisualChild(int index)
以返回特定的孩子。您可以查看ResizingAdorner MSDN示例以获取更多信息。
答案 1 :(得分:1)
了解WPF与Windows.Forms不同,这一点非常重要。 OnRender()
应该真正被称为AccumulateDrawingObjects()
,因为这是它正在做的事情。 WPF累积了一堆绘图对象,它保留以便能够在需要时绘制UI。有效更新UI的神奇之处在于,您可以在 OnRender()
之后实际更改中的对象。
例如,您可以制作DrawingGroup
" backingStore",并在DrawingContext
期间将其放入OnRender
。然后,只要你想要改变视觉效果,你可以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();
}