在WPF code。使用Dispatcher.Invoke prevent [英] Prevent using Dispatcher.Invoke in WPF code

查看:144
本文介绍了在WPF code。使用Dispatcher.Invoke prevent的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我生性是一个网络和后端程序员。通常我尝试做avaoid小程序。现在,我不得不作出一个WPF客户端。

I'm a web and backend programmer by nature. Normally I try to avaoid making windows programs. Now I have to make a WPF client.

我有一个引发事件的每一次常后台任务。 (它的工作就像一个轮询,当条件满足一个事件引发的)。小白,因为我我写的是附加到事件更新UI这个code。

I have a background task that raises an event every often time. (It is working like a poller and when the criteria are met an event is raised). Noob as I am I wrote this code that was attached to the event to update the UI.

    private void IsDisconnectedEvent()
    {
            UserWindow.Visibility = Visibility.Hidden;
            DisconnectWindow.Visibility = Visibility.Visible;
    }

因为我不是在同一个线程这给了一个例外。一些google搜索后,我发现,我应该改变code有:

This gives an exception because I am not on the same thread. After some googling I found that I should change the code with:

    private void IsDisconnectedEvent()
    {
        Dispatcher.Invoke(() =>
                          {
                              UserWindow.Visibility = Visibility.Hidden;
                              DisconnectWindow.Visibility = Visibility.Visible;
                          });
    }

这工作的,但是这不是唯一的事件,从而使我的code可怕的丑陋。有没有更好的方式来做到这一点?

This works, but this is not the only event and thus makes my code horrible ugly. Are there better ways to do this?

推荐答案

对于这个:

这工作的,但是这不是唯一的事件,从而使我的code
  可怕的丑

This works, but this is not the only event and thus makes my code horrible ugly

,您的基于WPF的code肯定是非常可怕的,除非你理解并接受 的WPF心态

Yes, your WPF-based code will definitely be extremely horrible unless you understand and embrace The WPF Mentality.

基本上,你的自定义逻辑(又名业务逻辑或应用程序逻辑)和WPF UI的之间的所有互动均应清单中的声明 数据绑定 ,而不是传统的势在必行的做法。

Basically, all interactions between your custom logic (AKA Business logic or Application Logic) and the WPF UI should manifest in the form of Declarative DataBinding as opposed to the traditional imperative approach.

这意味着,应该有这样的事:

This means that there should be nothing like this:

UserWindow.Visibility = Visibility.Hidden;

在code的任何地方,只是因为引进之类的东西,使你的code依赖于用户界面,因此只在UI线程上执行。

anywhere in your code, simply because introducing things like that makes your code dependent on the UI and thus only executable on the UI thread.

相反,WPF方法,它是通过声明的DataBind的能见度的UI元素的欢迎使用属性(在XAML )到相关的布尔属性,您可以从外部进行操作,像这样的:

Instead, the WPF approach to that would be to declaratively DataBind the Visibility propety of the UI element (IN XAML) to a relevant bool property that you can operate from the outside, like this:

<UserWindow Visibility="{Binding ShowUserWindow, Converter={my:BoolToVisibilityConverter}}">
   <!-- ... -->
</UserWindow>

然后,你需要创建一个包含UI期待绑定的属性相关的类。这就是所谓的 视图模型

请注意,为了正确地支持双向数据绑定WPF,你的ViewModels必须的实施 INotifyPropertyChanged的接口。

Notice that in order to properly support Two-Way WPF DataBinding, your ViewModels must Implement the INotifyPropertyChanged interface.

在这样做时,也方便有来自该接口的的PropertyChanged 活动的编组到UI线程,让你不再担心通过设置视图模型属性中的调度

When doing so, it is also convenient to have the PropertyChanged event from that interface marshalled to the UI thread, so that you no longer have to worry about setting the ViewModel's properties by using the Dispatcher.

因此​​,我们的第一步就是让我们所有的ViewModels从这样的类继承的:

Therefore our first step is to have all our ViewModels inherit from a class like this:

(从采取这个答案):

public class PropertyChangedBase:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        //Raise the PropertyChanged event on the UI Thread, with the relevant propertyName parameter:
        Application.Current.Dispatcher.BeginInvoke((Action) (() =>
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }));
    }
}

一旦我们有我们的属性更改通知调度到UI线程的到位,我们就可以着手创建一个适合在这种情况下, UserWindow ,它的数据绑定的预期:

Once we have our Property Change Notification Dispatch to the UI Thread in place, we can proceed to create a relevant ViewModel that suits, in this case, the UserWindow and it's DataBinding expectations:

public class UserViewModel: PropertyChangedBase
{
    private bool _showUserWindow;
    public bool ShowUserWindow
    {
        get {return _showUserWindow; }
        set
        {
            _showUserWindow = value;
            OnPropertyChanged("ShowUserWindow"); //This is important!!!
        }
    }
}

最后,你需要设置窗口的的 的DataContext 一个实例它对应的视图模型。一个简单的方法做到这一点是在窗口的构造函数:

Finally, you would need to set the Window's DataContext to an instance of it's corresponding ViewModel. One simple way to do that is in the Window's constructor:

public UserWindow() //Window's Constructor
{
    InitializeComponent();  //this is required.

    DataContext = new UserViewModel(); //here we set the DataContext
}

正如你可以看到在这个例子,有字面上的无需的操作过程中的code中的UI元素的属性。这不仅是一件好事,因为它解决了的线程关联的问题(因为现在你可以设置从任何线程的 ShowUserWindow 属性),而且还因为它使你的ViewModels和逻辑完全从用户界面分离的,因此可测试和更具扩展性。

As you can see in this example, there is literally no need to manipulate the UI element's properties in procedural code. This is good not only because it resolves the Thread Affinity issues (because now you can set the ShowUserWindow property from any thread), but also because it makes your ViewModels and logic completely decoupled from the UI and thus testable and more scalable.

这个概念同样适用于在WPF中的一切。

一个细节,我需要提到的是,我利用的合并的MarkupExtension 的IValueConverter 为了减少在XAML样板涉及到使用转换器。

One detail that I need to mention is that I'm making use of a technique of Combining MarkupExtension and IValueConverter in order to reduce the the XAML boilerplate involved in using Converters.

您可以在链接阅读更多关于这一点,并在MSDN数据绑定页面上面链接。

You can read more about that in the link and also the MSDN DataBinding page linked above.

让我知道如果你需要进一步的细节。

Let me know if you need further details.

这篇关于在WPF code。使用Dispatcher.Invoke prevent的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆