我读过许多关于绑定和GUI控件的线程亲和性的帖子,文章等。有些帖子中人们不想使用Dispatcher
。
我还有一位同事避免在他的代码中使用Dispatcher。我问他原因,但他的回答并不能让我满意。他说,他不喜欢隐藏在课堂上的这种“魔法”。
我是下一节课的粉丝。
public class BindingBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Dispatcher Dispatcher
{
#if SILVERLIGHT
get { return Deployment.Current.Dispatcher; }
#else
get { return Application.Current.Dispatcher; }
#endif
}
protected void RaisePropertyChanged<T>(Expression<Func<T>> expr)
{
var memberExpr = (MemberExpression)expr.Body;
string property = memberExpr.Member.Name;
var propertyChanged = PropertyChanged;
if (propertyChanged == null) return;
if (Dispatcher.CheckAccess())
propertyChanged.Invoke(this, new PropertyChangedEventArgs(property));
else
Dispatcher.BeginInvoke(() => RaisePropertyChanged(expr));
}
}
这是一个问题。有些人不想使用这样的课程有什么理由吗?也许我必须重新考虑这种方法。
你必须承认,有一件奇怪的事情。 Intellisense排除Dispatcher.CheckAccess()
。也许由于这个事实,他们有点可怕。
此致
修改
好的,另一个例子。考虑一个复杂的对象。作为例子的集合可能不是最好的主意。
public class ExampleVm : BindingBase
{
private BigFatObject _someData;
public BigFatObject SomeData
{
get { return _someData; }
set
{
_someData = value;
RaisePropertyChanged(() => SomeData);
}
}
public ExampleVm()
{
new Action(LoadSomeData).BeginInvoke(null, null); //I know - it's quick and dirty
}
private void LoadSomeData()
{
// loading some data from somewhere ...
// result is of type BigFatObject
SomeData = result; // This would not work without the Dispatcher, would it?
}
}
答案 0 :(得分:5)
我个人也不反对视图模型类中的Dispatcher
。我没有看到任何重大问题,但它为您的代码提供了最大的灵活性。
但我喜欢尽可能将Dispatcher
的用法封装在基础架构代码中的想法。就像你使用RaisePropertyChanged
方法一样(顺便说一句,在RaisePropertyChanged
的情况下你不需要发送任何东西 - 绑定已经为你做了;你只需要对集合发送更改)。
我在这里看到的最大和唯一的缺点是单元测试。当您尝试测试涉及Dispatcher
使用的逻辑时,事情会变得棘手。想象一下,如果你在视图模型中有类似的代码:
private void UpdateMyCollection()
{
IList<ModelData> dataItems = DataService.GetItems();
// Update data on UI
Dispatcher.BeginInvoke(new Action(() => {
foreach (ModelData dataItem in dataItems)
{
MyObservableCollection.Add(new DataItemViewModel(dataItem));
}
}));
}
这种代码在从非UI线程更新集合时非常典型。现在,您将如何编写单元测试来测试向可观察集合添加项目的逻辑?首先,您需要模拟Dispatcher
属性,因为Application.Current
在单元测试执行期间是null
。第二,你将如何嘲笑它?你会创建一个特殊的线程来模仿UI线程并使用该线程的Dispatcher
吗?所以,这种事情。
最重要的是,如果您希望代码对单元测试友好,则需要考虑如何模拟Dispatcher
的方式。这是唯一的问题。
<强>更新强>
您提供的第二个示例将在没有Dispatcher
的情况下工作(绑定将起作用)。