是否可以在给定区域而不是整个WPF控件上使evisual()无效?
我有一个复杂的WPF控件,它在OnRender中绘制了很多基本体(有点像地图)。当其中一小部分发生更改时,我只想为受影响的元素重新发出渲染命令,而不是运行整个OnRender。虽然我对OnRender函数在调整大小或其他方面的性能很满意,但对于基于鼠标悬停的基本体高亮显示来说,它的速度还不够快 目前,我知道如何强制屏幕更新的唯一方法是调用InvalidateVisual()。无法发送脏rect区域以使其无效是否可以在给定区域而不是整个WPF控件上使evisual()无效?,wpf,user-interface,rendering,Wpf,User Interface,Rendering,我有一个复杂的WPF控件,它在OnRender中绘制了很多基本体(有点像地图)。当其中一小部分发生更改时,我只想为受影响的元素重新发出渲染命令,而不是运行整个OnRender。虽然我对OnRender函数在调整大小或其他方面的性能很满意,但对于基于鼠标悬停的基本体高亮显示来说,它的速度还不够快 目前,我知道如何强制屏幕更新的唯一方法是调用InvalidateVisual()。无法发送脏rect区域以使其无效 WPF屏幕组成的最低粒度是UI元素吗?我是否需要将基本体渲染到中间目标,然后使用Inva
WPF屏幕组成的最低粒度是UI元素吗?我是否需要将基本体渲染到中间目标,然后使用InvalidateVisual()将其更新到屏幕上?WPF的工作方式与此不同,因此无法使区域无效。但是,可以进行一些优化。有一个测量、排列,然后渲染过程。如果控件移动,但实际渲染的内容不变,则可以告诉WPF仅执行排列过程。您可以使用FrameworkPropertyMetadata和FrameworkPropertyMetadataOptions()触发这些依赖项属性值更改无效。当您想编写WPF自定义/复合控件时,应尽量避免重写OnRender,特别是如果您计划使其部分无效。使用AddVisualChild+override VisualChildrenCount+override GetVisualChild+override Measure和排列方式更容易(包含两个子项的伪代码):
使用这种代码,您可以使用类似subcrolx.InvalidateXXX()的命令使一部分无效 除非控件的大小发生变化,否则不应使用
InvalidateVisual()
,因为它会导致相当昂贵的UI重新布局
WPF是一个保留的绘图系统。这意味着OnRender()
最好调用AccumeratedRawingObjects()
。它实际上是在累积一个动态图形对象树,每个布局只需要发生一次。然后,它会在需要时使用这些对象来绘制UI。要在不重新布局的情况下更改部分UI的外观,可以在OnRender()
之后随时更新某些对象(如DrawingGroup、RenderTargetBitmap和WriteableBitmap)
要在以后更新部分UI,请将这些命令包装在DrawingGroup
中,并将该对象放入DrawingContext
中。然后您可以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();
}
是否覆盖UIElement.OnRender以绘制UIElement内的所有内容,或者该元素是否仍具有正常的视觉子元素?
MeasureCore
和ArrangeCore
不可覆盖。也许你想说MeasureOverride
和ArrangeOverride
?@dotnet-这取决于你是从UIElement还是FrameworkElement派生的
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();
}