【问题标题】:How to invalidate visual on dependency property changed?如何使依赖属性更改的视觉无效?
【发布时间】:2013-03-19 03:00:54
【问题描述】:

我有自定义控件,重写了 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 计算哈希的原因。我没有看到其他方式,因为我需要跟踪不同的内部属性。

标签: .net wpf controls dependency-properties


【解决方案1】:

恕我直言,最好的方法是在您使用的 DependencyProperties 上指定它们会影响渲染。

请参阅 FrameworkPropertyMetadata.AffectsRender:http://msdn.microsoft.com/en-us/library/system.windows.frameworkpropertymetadata.aspx

【讨论】:

    【解决方案2】:

    当然,最快的方法是走脏路并这样做

    (DataContext as INotifyPropertyChanged).PropertyChanged += OnPropertiesChanged
    
    private void OnPropertiesChanged(sender, args)
    {
        InvalidateVisual();
    }
    

    但我强烈建议您不要这样做。另一方面,恕我直言更好的解决方案有点受限。尝试更改您的自定义依赖项属性,使其与渲染相关,因为您可以在创建依赖项属性时提供标志 AffectsRender。 现在你说“来自父类型的属性”我没有得到那个部分,但我想你的意思是一个带有子视图模型的父视图模型。如果您相应地设计属性,这无关紧要。 如果由于某种原因该解决方案不起作用,您可以在视图模型上仅使用一个属性,绑定到视图中具有 AffectsRender 标志的依赖项属性,并在视图应该重绘时将其设置在您的视图模型逻辑中,但是这又是一种肮脏的方式。

    也不要太想使用 OnRender 方法进行大量绘图,我们在大型应用程序中使用 WPF,我们可能有一两个地方使用 OnRender,其他一切都通过样式和模板。

    【讨论】:

    • 我也忙于几个大项目,几乎所有的 UI 都是用样式和模板完成的。但是如果你想绘制图表或一些非常复杂的东西,你必须使用 OnRender,否则性能会非常糟糕。
    • 没错,但如果性能真的那么重要,我会一起跳过“控制”。虽然您仍然可以从 Visuals 中获得很多性能,但也许 WriteableBitmap 也值得考虑。
    【解决方案3】:

    如果您的控件的大小没有改变,InvalidateVisual() 会非常昂贵,因为它会导致控件树的完全重新布局。

    如果大小保持不变,使用某些保留模式绘图对象可以在OnRender() 期间输出后更新这一事实会更有效。例如,DrawingGroupWriteableBitmapRenderTargetBitmap 都可以在OnRender() 期间输出它们之后进行更新

    在大多数情况下,您会创建一个DrawingGroup“backingStore”,在OnRender() 期间输出它,然后您可以随时通过执行backingStore.Open() 更新控件的视觉效果并将新的绘图命令放入@987654330 @。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-15
      • 1970-01-01
      • 2011-01-29
      • 1970-01-01
      • 2017-08-05
      • 1970-01-01
      相关资源
      最近更新 更多