Wpf 多线程视图模型
我有一个实现向导功能的NavigationWindow和一组表示步骤的页面对象 每个页面使用单独的视图模型 其中一些视图模型从其构造函数中生成工作线程。我在处理视图模型时终止这些线程(它们实现IDisposable) 此外,我在页面的构造函数中将这些视图模型分配给页面的DataContext,并在卸载的事件上处理DataContext。我这样做是因为我需要停止工作线程 只要我不想在向导中导航回来,所有这些都可以正常工作。但是如果我这样做了,页面,因为它已经被卸载过,不再有DataContext,也不会显示任何内容 因此,为了解决这个问题,我不需要在卸载时处理DataContext,而是指示视图模型在其所属窗口被加载/卸载时启动/停止其线程。为此,我想我需要在视图模型上引入几个方法(比如Start()和Stop())来实现这一点。并从页面的初始化和卸载处理程序中调用这些方法 但这很难看。这太复杂了,页面需要知道如何启动/停止线程,否则将无法工作。因此,我正在寻找正确的MVVM方法来实现这一点 请帮忙Wpf 多线程视图模型,wpf,mvvm,Wpf,Mvvm,我有一个实现向导功能的NavigationWindow和一组表示步骤的页面对象 每个页面使用单独的视图模型 其中一些视图模型从其构造函数中生成工作线程。我在处理视图模型时终止这些线程(它们实现IDisposable) 此外,我在页面的构造函数中将这些视图模型分配给页面的DataContext,并在卸载的事件上处理DataContext。我这样做是因为我需要停止工作线程 只要我不想在向导中导航回来,所有这些都可以正常工作。但是如果我这样做了,页面,因为它已经被卸载过,不再有DataContext,
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}" />