Wpf 多线程视图模型

Wpf 多线程视图模型,wpf,mvvm,Wpf,Mvvm,我有一个实现向导功能的NavigationWindow和一组表示步骤的页面对象 每个页面使用单独的视图模型 其中一些视图模型从其构造函数中生成工作线程。我在处理视图模型时终止这些线程(它们实现IDisposable) 此外,我在页面的构造函数中将这些视图模型分配给页面的DataContext,并在卸载的事件上处理DataContext。我这样做是因为我需要停止工作线程 只要我不想在向导中导航回来,所有这些都可以正常工作。但是如果我这样做了,页面,因为它已经被卸载过,不再有DataContext,

我有一个实现向导功能的NavigationWindow和一组表示步骤的页面对象

每个页面使用单独的视图模型

其中一些视图模型从其构造函数中生成工作线程。我在处理视图模型时终止这些线程(它们实现IDisposable)

此外,我在页面的构造函数中将这些视图模型分配给页面的DataContext,并在卸载的事件上处理DataContext。我这样做是因为我需要停止工作线程

只要我不想在向导中导航回来,所有这些都可以正常工作。但是如果我这样做了,页面,因为它已经被卸载过,不再有DataContext,也不会显示任何内容

因此,为了解决这个问题,我不需要在卸载时处理DataContext,而是指示视图模型在其所属窗口被加载/卸载时启动/停止其线程。为此,我想我需要在视图模型上引入几个方法(比如Start()和Stop())来实现这一点。并从页面的初始化和卸载处理程序中调用这些方法

但这很难看。这太复杂了,页面需要知道如何启动/停止线程,否则将无法工作。因此,我正在寻找正确的MVVM方法来实现这一点

请帮忙
konstantin

问题似乎在于视图模型依赖于视图的生命周期-这自动意味着视图将通知视图模型状态转换。目标是找到这些变化的最佳表现形式

第一步是重新构建交互框架:
Start()
Stop()
是必不可少的概念,我同意,它们确实让人感到沉重。相反,让我们考虑一下作为状态机我们在做什么。我将假设您的线程正在进行某种侦听,因此我们的状态可能是
侦听
空闲
,以及
完成
。它们分别对应于正在运行的线程、暂停的线程和准备终止的线程

表示状态的可靠方法是枚举:

public enum ListenerState
{
    Idle,

    Listening,

    Complete
}
您将在视图模型上声明此类型的属性:

public class ListenerModel : ViewModel
{
    private ListenerState _state;

    public ListenerState State
    {
        get { return _state; }
        set
        {
            _state = value;

            RaisePropertyChanged("State");
        }
    }
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
    this.ListenerState = ListenerState.Listening;
}
然后,您将侦听状态的更改并更新线程以匹配:

protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
    if(e.PropertyName == "State")
    {
        // Manipulate thread for current state
    }
}
现在,视图只需向视图模型通知生命周期事件(视图模型除了从视图中知道之外,无法通过其他方式知道):

如果要将视图与视图模型完全解耦,可以在控件中为状态创建依赖项属性:

public static readonly DependencyProperty ListenerStateProperty =
    DependencyProperty.Register("ListenerState", typeof(ListenerState), typeof(YourControl), null);

public ListenerState ListenerState
{
    get { return (ListenerState) GetValue(ListenerStateProperty); }
    set { SetValue(ListenerStateProperty, value); }
}
然后,在加载的处理程序中设置该属性,而不是引用视图模型:

public class ListenerModel : ViewModel
{
    private ListenerState _state;

    public ListenerState State
    {
        get { return _state; }
        set
        {
            _state = value;

            RaisePropertyChanged("State");
        }
    }
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
    this.ListenerState = ListenerState.Listening;
}
最后,将属性绑定到标记中视图模型的属性:

<local:YourControl ListenerState="{Binding State, Mode=TwoWay}" />

问题似乎在于视图模型依赖于视图的生命周期-这自动意味着视图将通知视图模型状态转换。目标是找到这些变化的最佳表现形式

第一步是重新构建交互框架:
Start()
Stop()
是必不可少的概念,我同意,它们确实让人感到沉重。相反,让我们考虑一下作为状态机我们在做什么。我将假设您的线程正在进行某种侦听,因此我们的状态可能是
侦听
空闲
,以及
完成
。它们分别对应于正在运行的线程、暂停的线程和准备终止的线程

表示状态的可靠方法是枚举:

public enum ListenerState
{
    Idle,

    Listening,

    Complete
}
您将在视图模型上声明此类型的属性:

public class ListenerModel : ViewModel
{
    private ListenerState _state;

    public ListenerState State
    {
        get { return _state; }
        set
        {
            _state = value;

            RaisePropertyChanged("State");
        }
    }
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
    this.ListenerState = ListenerState.Listening;
}
然后,您将侦听状态的更改并更新线程以匹配:

protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
    if(e.PropertyName == "State")
    {
        // Manipulate thread for current state
    }
}
现在,视图只需向视图模型通知生命周期事件(视图模型除了从视图中知道之外,无法通过其他方式知道):

如果要将视图与视图模型完全解耦,可以在控件中为状态创建依赖项属性:

public static readonly DependencyProperty ListenerStateProperty =
    DependencyProperty.Register("ListenerState", typeof(ListenerState), typeof(YourControl), null);

public ListenerState ListenerState
{
    get { return (ListenerState) GetValue(ListenerStateProperty); }
    set { SetValue(ListenerStateProperty, value); }
}
然后,在加载的处理程序中设置该属性,而不是引用视图模型:

public class ListenerModel : ViewModel
{
    private ListenerState _state;

    public ListenerState State
    {
        get { return _state; }
        set
        {
            _state = value;

            RaisePropertyChanged("State");
        }
    }
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
    this.ListenerState = ListenerState.Listening;
}
最后,将属性绑定到标记中视图模型的属性:

<local:YourControl ListenerState="{Binding State, Mode=TwoWay}" />