C# 防止在WPF代码中使用Dispatcher.Invoke
我天生就是一名网络和后端程序员。通常情况下,我会尽量避免制作windows程序。现在我要做一个WPF客户端 我有一个背景任务,每次都会引发一个事件。(它像一个民意测验者一样工作,当满足标准时,就会引发一个事件)。尽管我是Noob,我还是编写了这个附在事件上的代码来更新UIC# 防止在WPF代码中使用Dispatcher.Invoke,c#,wpf,C#,Wpf,我天生就是一名网络和后端程序员。通常情况下,我会尽量避免制作windows程序。现在我要做一个WPF客户端 我有一个背景任务,每次都会引发一个事件。(它像一个民意测验者一样工作,当满足标准时,就会引发一个事件)。尽管我是Noob,我还是编写了这个附在事件上的代码来更新UI private void IsDisconnectedEvent() { UserWindow.Visibility = Visibility.Hidden; D
private void IsDisconnectedEvent()
{
UserWindow.Visibility = Visibility.Hidden;
DisconnectWindow.Visibility = Visibility.Visible;
}
这是一个例外,因为我不在同一个线程上。在谷歌搜索之后,我发现我应该用以下方法更改代码:
private void IsDisconnectedEvent()
{
Dispatcher.Invoke(() =>
{
UserWindow.Visibility = Visibility.Hidden;
DisconnectWindow.Visibility = Visibility.Visible;
});
}
这是可行的,但这并不是唯一的事件,因此我的代码非常难看。有更好的方法吗?关于这一点:
这是可行的,但这不是唯一的事件,因此我的代码
可怕的丑陋
是的,除非您理解并接受,否则基于WPF的代码肯定会非常糟糕
基本上,您的自定义逻辑(又名业务逻辑或应用程序逻辑)和WPF UI之间的所有交互都应该以声明性的形式体现,而不是传统的命令式方法
这意味着不应该有这样的情况:
UserWindow.Visibility = Visibility.Hidden;
<UserWindow Visibility="{Binding ShowUserWindow, Converter={my:BoolToVisibilityConverter}}">
<!-- ... -->
</UserWindow>
在代码中的任何位置,这仅仅是因为引入这样的东西会使代码依赖于UI,因此只能在UI线程上执行
相反,WPF的方法是将UI元素(在XAML中)的可见性
属性声明性地数据绑定到可以从外部操作的相关bool属性,如下所示:
UserWindow.Visibility = Visibility.Hidden;
<UserWindow Visibility="{Binding ShowUserWindow, Converter={my:BoolToVisibilityConverter}}">
<!-- ... -->
</UserWindow>
一旦我们将属性更改通知分派到UI线程,我们就可以继续创建一个相关的ViewModel,该ViewModel在本例中适用于UserWindow
及其数据绑定预期:
public class UserViewModel: PropertyChangedBase
{
private bool _showUserWindow;
public bool ShowUserWindow
{
get {return _showUserWindow; }
set
{
_showUserWindow = value;
OnPropertyChanged("ShowUserWindow"); //This is important!!!
}
}
}
最后,您需要将窗口设置为其相应ViewModel的实例。一种简单的方法是在窗口的构造函数中:
public UserWindow() //Window's Constructor
{
InitializeComponent(); //this is required.
DataContext = new UserViewModel(); //here we set the DataContext
}
正如您在本例中所看到的,实际上不需要在过程代码中操纵UI元素的属性。这不仅是因为它解决了线程关联性问题(因为现在您可以从任何线程设置ShowUserWindow
属性),而且还因为它使您的ViewModels和逻辑与UI完全解耦,因此可测试性和可伸缩性更高
同样的概念也适用于WPF中的所有内容。
我需要提到的一个细节是,为了减少使用转换器所涉及的XAML样板文件,我正在使用一种技术
您可以在链接和上面链接的MSDN数据绑定页面中了解更多信息
如果您需要更多详细信息,请告诉我。您可以使用
后台工作人员。除此之外,Dispatcher.Invoke()
是一个不错的选择。此外,您还可以将Dispatcher调用包装到一个方法中,例如,PropagateChangesToUI(UIState newState){Dispatcher.Invoke([…]);}
。它们专门用于各种任务,因此您使用哪一个取决于您正在做什么。如果您正在按进度进行更新,请使用IProgress
,如果您在一段时间后调用代码,请使用dispatchermer
,如果您在后台线程中执行CPU限制的工作,则可以使用BackgroundWorker
。依此类推。-1从我看来,这是一个很好的答案,但我不同意wpf完全是关于mvvm模式的。mvvm是一种模式,就是这样,只是一种模式。wpf也可以与mvp模式一起使用,这也只是一种模式。当然,比起wpf和mvp,wpf和mvvm更喜欢彼此,但我仍然不同意您如此强制使用mvvm模式。这就像说所有在winforms中开发ui应用程序的人都是傻瓜和马一样:)呵呵,你不知道mvp是什么?伙计。。。无可奉告:)@devhedgehog我是在讽刺老兄。。。我知道什么是MVP,但我完全忽略了这一点,因为这与我完全无关。。你现在明白了吗?你描述它的方式听起来像是我在寻找的。使用Web应用程序,我构建了具有清晰关注点分离的MVC应用程序。我会去阅读有关MVVM的文章,我想这会让我走得更远……WPF会自动将所有PropertyChanged事件封送到UI线程,Dispatcher.BeginInvoke没有任何意义。但是,对于第二个主WPF事件-CollectionChanged,情况并非如此。