如何在MVVM视图模型中处理c#WPF线程

时间:2022-11-10 20:56:10

I am having a bear of a time figuring out how to handle a Thread from a class outside my ViewModel.

我正在考虑如何处理来自ViewModel之外的类的Thread。

The Thread originates from a Track class. Here is the ResponseEventHandler code in Track:

Thread来自Track类。这是Track中的ResponseEventHandler代码:

public delegate void ResponseEventHandler(AbstractResponse response);
public event ResponseEventHandler OnResponseEvent;

When a "command" method is processed from within my Track object, the following code runs the OnResponseEvent, which sends a message in a Thread back to my ViewModel:

从我的Track对象中处理“command”方法时,以下代码运行OnResponseEvent,它将Thread中的消息发送回我的ViewModel:

if (OnResponseEvent != null)
{
    OnResponseEvent(GetResponseFromCurrentBuffer());
}

GetResponseFromCurrentBuffer() merely returns a message type which is a pre-defined type within the Track.

GetResponseFromCurrentBuffer()仅返回消息类型,该类型是Track中的预定义类型。

My MainWindowViewModel constructor creates an event handler for the OnResponseEvent from the Track:

我的MainWindowViewModel构造函数从Track创建OnResponseEvent的事件处理程序:

public MainWindowViewModel()
{
    Track _Track = new Track();

    _Track.OnResponseEvent +=
        new Track.ResponseEventHandler(UpdateTrackResponseWindow);
}

So, the idea is that every time I have a new message coming from the OnResponseEvent Thread, I run the UpdateTrackResponseWindow() method. This method will append a new message string to an ObservableCollection<string> list property called TrackResponseMessage:

因此,我的想法是,每当我从OnResponseEvent线程获得新消息时,我都会运行UpdateTrackResponseWindow()方法。此方法将新消息字符串附加到名为TrackResponseMessage的ObservableCollection 列表属性:

private void UpdateTrackResponseWindow(AbstractResponse message)
{
    TrackResponseMessage.Add(FormatMessageResponseToString(message));
}

The FormatMessageResponseToString() method merely compares the message with all pre-defined message types within the Track, and does some nifty string formatting.

FormatMessageResponseToString()方法仅将消息与Track中的所有预定义消息类型进行比较,并进行一些漂亮的字符串格式化。

The main problem is: The UI disappears when TrackResponseMessage.Add() is run. The executable is still running in the background, and the only way to end the task is to shut down Visual Studio 2010.

主要问题是:运行TrackResponseMessage.Add()时,UI会消失。可执行文件仍在后台运行,结束任务的唯一方法是关闭Visual Studio 2010。

TrackResponseMessage is a public property within my ViewModel:

TrackResponseMessage是我的ViewModel中的公共属性:

public ObservableCollection<String> TrackResponseMessage
{
    get { return _trackResponseMessage; }
    set
    {
        _trackResponseMessage = value;
        RaisePropertyChanged("TrackResponseMessage");
    }
}

Is there a need for me to marshal the Thread coming from the Track object to my ViewModel? Any example code would be very appreciated!

是否需要将来自Track对象的Thread封送到我的ViewModel?任何示例代码将非常感谢!

2 个解决方案

#1


9  

Is there a need for me to marshall the thread comming from the Track.cs object to my viewmodel? Any example code would be very appreciated!

我是否需要编组从Track.cs对象到我的viewmodel的线程?任何示例代码将非常感谢!

Yes. Unfortunately, while INotifyPropertyChanged will handle events from other threads, INotifyCollectionChanged does not (ie: ObservableCollection<T>). As such, you need to marshal back to the VM.

是。不幸的是,虽然INotifyPropertyChanged将处理来自其他线程的事件,但INotifyCollectionChanged却没有(即:ObservableCollection )。因此,您需要编组回VM。

If the VM is being create from the View (View-First MVVM) or is known to be created on the UI thread, there's a good option using .NET 4 tasks:

如果从View(View-First MVVM)创建VM或者已知在UI线程上创建VM,则使用.NET 4任务有一个很好的选择:

TaskScheduler uiScheduler;
public MainWindowViewModel() 
{
    uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Track _Track = new Track();
    _Track.OnResponseEvent += new Track.ResponseEventHandler(UpdateTrackResponseWindow);
}

Then, later, your event handler can do:

然后,您的事件处理程序可以执行以下操作:

private void UpdateTrackResponseWindow(AbstractResponse message) 
{
    Task.Factory.StartNew(
       () => TrackResponseMessage.Add(FormatMessageResponseToString(message)),
       CancellationToken.None, TaskCreationOptions.None,
       uiScheduler); 
}

This has the nice advantage of not pulling WPF or Silverlight specific resources and types into your ViewModel class (ie: Dispatcher), while still providing all of the benefits. It also works, unchanged, in other routines with thread affinity (ie: WCF service work).

这样做的好处是不会将WPF或Silverlight特定的资源和类型提取到ViewModel类(即:Dispatcher),同时仍然提供所有好处。它在具有线程亲和性的其他例程中也可以不变地工作(即:WCF服务工作)。

#2


0  

If the RaisePropertychanged is executed on a thread other than the UI thread AND the event handler for the event touches the UI you need to switch to the UI thread.

如果在UI线程以外的线程上执行RaisePropertychanged并且事件的事件处理程序触及UI,则需要切换到UI线程。

#1


9  

Is there a need for me to marshall the thread comming from the Track.cs object to my viewmodel? Any example code would be very appreciated!

我是否需要编组从Track.cs对象到我的viewmodel的线程?任何示例代码将非常感谢!

Yes. Unfortunately, while INotifyPropertyChanged will handle events from other threads, INotifyCollectionChanged does not (ie: ObservableCollection<T>). As such, you need to marshal back to the VM.

是。不幸的是,虽然INotifyPropertyChanged将处理来自其他线程的事件,但INotifyCollectionChanged却没有(即:ObservableCollection )。因此,您需要编组回VM。

If the VM is being create from the View (View-First MVVM) or is known to be created on the UI thread, there's a good option using .NET 4 tasks:

如果从View(View-First MVVM)创建VM或者已知在UI线程上创建VM,则使用.NET 4任务有一个很好的选择:

TaskScheduler uiScheduler;
public MainWindowViewModel() 
{
    uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Track _Track = new Track();
    _Track.OnResponseEvent += new Track.ResponseEventHandler(UpdateTrackResponseWindow);
}

Then, later, your event handler can do:

然后,您的事件处理程序可以执行以下操作:

private void UpdateTrackResponseWindow(AbstractResponse message) 
{
    Task.Factory.StartNew(
       () => TrackResponseMessage.Add(FormatMessageResponseToString(message)),
       CancellationToken.None, TaskCreationOptions.None,
       uiScheduler); 
}

This has the nice advantage of not pulling WPF or Silverlight specific resources and types into your ViewModel class (ie: Dispatcher), while still providing all of the benefits. It also works, unchanged, in other routines with thread affinity (ie: WCF service work).

这样做的好处是不会将WPF或Silverlight特定的资源和类型提取到ViewModel类(即:Dispatcher),同时仍然提供所有好处。它在具有线程亲和性的其他例程中也可以不变地工作(即:WCF服务工作)。

#2


0  

If the RaisePropertychanged is executed on a thread other than the UI thread AND the event handler for the event touches the UI you need to switch to the UI thread.

如果在UI线程以外的线程上执行RaisePropertychanged并且事件的事件处理程序触及UI,则需要切换到UI线程。