2013-07-23 54 views
0

我正在WPF中编写自定义控件。该控件具有多个属性,可以更新控件的逻辑树。有这种形式的几种方法:避免频繁更新WPF自定义控件

private static void OnXXXPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
{ 
    ((MyControl)obj).RebuildTree(); 
} 

假设RebuildTree()方法是非常复杂的,lenghty如果用户改变了几个属性,这种方法称为多次造成应用减速和悬挂。

我想介绍一些类似于BeginUpdate()EndUpdate()方法的Windows窗体方式(以确保更新只被调用一次),但是这种做法在WPF中被广泛阻挡。

我知道渲染具有较低的优先级和闪烁可能不会出现,但仍为什么要通过调用相同的更新方法多次糟蹋宝贵的运行时间?

是否有关于如何进行多依赖属性的有效的更新任何官方的最佳实践(而不更新设置每一个后整个控制)?

+0

张贴了'RebuildTree()'方法的代码。另外,你的自定义控件是做什么的? –

+0

@HighCore该方法创建一个复杂的3D模型(大量点),然后创建几个控件,每个控件都具有自定义着色器效果。我没有一个完整的代码,但我想解决这个一般问题(例如,想象一下,每次调用它时,该方法都会创建1 000个控件)。我希望应用程序在所有属性都设置完毕后才向用户显示最终结果,而不是中间步骤以及所有应该在“引擎盖下”发生的事情。 – Libor

回答

2

只需设置一个标志,当这些属性发生了变化,并有刷新方法排队到调度一次。

private static void OnXXXPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
{ 
    ((MyControl)obj).NeedsRefresh = true; 
    ((MyControl)obj).OnNeedsRefresh(); 
} 

void OnNeedsRefresh() 
{ 
    Dispatcher.BeginInvoke((Action)(() => 
    { 
    if (NeedsRefresh) 
    { 
     NeedsRefresh = false; 
     RebuildTree(); 
    } 
    }),DispatcherPriority.ContextIdle); 
} 

这样一来,所有的属性将被更新,然后调度人员会打电话给你BeginInvoke,该标志设置为false,并刷新一次。

+0

一个聪明的把戏。还有一个缺点:在设置完第一个属性之后,刷新完成,并且由于'NeedsRefresh'标志,所以其他刷新调用被避免。 _last_属性设置后,理想状态将会更新。不管怎么说,还是要谢谢你。也许在'Binding'中有''Delay''属性,在提交任何更改之前会等待一定的时间。但是如果在WPF中没有标准的方法,我会添加自定义的'BeginUpdate'和'EndUpdate' - 这会使用户得到最优化。 – Libor

+0

@Libor'还有一个缺点是,在设置完第一个属性后刷新完成,其他调用因为NeedsRefresh标志而被删除 - 我不明白。 ContextIdle优先级应该强制所有绑定更新PRIOR来调用Refresh()。这就是你想要的吗? –

+0

哦,我明白了。我会尝试优先级设置。 – Libor