如何在依赖属性更改时使视觉效果无效?

3

我有一个自定义控件,其中包含被重写的 OnRender 方法。我想在任何依赖属性更改事件中使控件无效。当父类型的属性更改时,也希望更新。是否有内置功能可以实现这一点?

编辑:

我发现我可以同时使用“影响渲染”来处理依赖属性,并在 OnLayoutUpdated 上检查其他信息或私有属性。

FrameworkPropertyMetadata.AffectsRender

并且:

private void OnLayoutUpdated(object sender, EventArgs e)
    {
        int result = (CornerRadius != null ? CornerRadius.GetHashCode() : 0);
        result = (result * PrimeHashNumber) ^ (IsSelected.GetHashCode());
        result = (result * PrimeHashNumber) ^ (IsReadCornerRadiusFromConfig.GetHashCode());
        result = (result * PrimeHashNumber) ^ (IsReadBorderThicknessFromConfig.GetHashCode());
        result = (result * PrimeHashNumber) ^ (SelectedColor!=null?SelectedColor.GetHashCode():0);
        result = (result * PrimeHashNumber) ^ (Background != null ? Background.GetHashCode() : 0);
        result = (result * PrimeHashNumber) ^ (BorderBrush != null ? BorderBrush.GetHashCode() : 0);
        
        if (lastHash != result)
        {
            this.InvalidateVisual();
            lastHash = result;
        }
    }

我不会使用LayoutUpdated来做这个,因为它的触发频率比你想象的要高得多。它被调用的次数非常频繁,以至于给人一种“感觉”是正确的位置,但是在使用它时可能会遇到一些性能问题。 - dowhilefor
@dowhilefor 那就是为什么要计算哈希值。我没有看到其他的方法,因为我需要跟踪不同的内部属性。 - Ievgen
3个回答

5

2
当然最快的方式是走一条不太好的路,这样做。
(DataContext as INotifyPropertyChanged).PropertyChanged += OnPropertiesChanged

private void OnPropertiesChanged(sender, args)
{
    InvalidateVisual();
}

但我强烈建议您不要这样做。我认为更好的解决方案是稍微受限制的。尝试更改自定义依赖属性,使其与渲染相关,可以在创建依赖属性时提供标志AffectsRender。 现在你说“来自父类型的属性”,我不明白那部分,但我想你是指具有子视图模型的父视图模型。如果您根据需要设计属性,则不应该有问题。 如果由于某种原因该解决方案无效,则可以在视图模型上使用一个属性,将其绑定到视图中具有AffectsRender标志的依赖属性,并在视图模型逻辑中设置它,以便在视图需要重新绘制时使用,但我认为这是不好的方法。 此外,不要过度使用OnRender方法进行绘图,在我们的大型应用程序中,我们可能只有一两个地方使用OnRender,其他所有内容都是通过样式和模板完成的。

我也忙于几个大项目,几乎所有的 UI 都是使用样式和模板完成的。但是如果你想绘制图表或者其他真正复杂的东西,你必须使用 OnRender,否则性能会非常差。 - Ievgen
1
没错,但如果性能真的很重要,我会完全跳过“控件”。虽然你仍然可以从可视化对象中获得很高的性能,但也许值得考虑 WriteableBitmap - dowhilefor

1
如果您的控件大小不改变,InvalidateVisual()将非常昂贵,因为它会导致控件树的完整重新布局。
如果大小保持不变,则更有效地利用某些保留模式绘图对象可以在OnRender()期间输出后进行更新的事实。例如,DrawingGroupWriteableBitmapRenderTargetBitmap都可以在OnRender()期间输出后进行更新。
在大多数情况下,您将创建一个DrawingGroup "backingStore",在OnRender()期间输出它,然后您可以通过执行backingStore.Open()并将新的绘图命令放入DrawingGroup来随时更新控件的可视化效果。

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