我有一个实现向导功能的NavigationWindow,以及一组表示步骤的页面对象。
每个Page使用一个单独的视图模型。
其中一些视图模型从它们的构造函数中产生工作线程。我在处理视图模型时终止这些线程(它们实现了IDisposable)。
此外,我在页面的构造函数中将这些视图模型分配给页面的DataContext,并在Unloaded事件上处理DataContext。我这样做是因为我需要停止工作线程。
只要我不想回到向导中,所有这些都可以正常工作。但如果我这样做了,页面就不再有DataContext,也不会显示任何内容,因为它以前已经卸载过。
因此,要解决这个问题,我不需要在卸载时处理DataContext,而是指示视图模型在其拥有的窗口加载/卸载时启动/停止它的线程。为此,我需要在视图模型上引入几个方法(比如Start()和Stop())来实现这一点。并从页面的初始化和卸载处理程序调用这些方法。
但这太丑陋了。它太复杂了,页面需要知道如何启动/停止线程,否则它将无法工作。因此,我正在寻找正确的MVVM方法来实现这一点。
请帮帮康斯坦丁
发布于 2010-10-13 23:57:07
听起来问题似乎是视图模型依赖于视图的生命周期-这自动意味着视图将通知视图模型状态转换。我们的目标是找到这些变化的最佳代表。
第一步是重新构建交互:Start()和Stop()是势在必行的概念,我同意,这确实让人感觉沉重。相反,让我们考虑一下我们作为状态机在做什么。我假设您的线程正在进行某种侦听,因此我们的状态可能是Listening、Idle和Complete。它们将分别对应于正在运行的线程、暂停的线程和准备终止的线程。
表示状态的可靠方法是枚举:
public enum ListenerState
{
Idle,
Listening,
Complete
}您可以在视图模型上声明此类型的属性:
public class ListenerModel : ViewModel
{
private ListenerState _state;
public ListenerState State
{
get { return _state; }
set
{
_state = value;
RaisePropertyChanged("State");
}
}
}然后,您将监听状态的更改并更新线程以匹配:
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if(e.PropertyName == "State")
{
// Manipulate thread for current state
}
}现在,视图只需通知视图模型生命周期事件(除了视图之外,视图模型不能通过任何其他方式了解这些事件):
private void OnLoaded(object sender, RoutedEventArgs e)
{
((ListenerModel) this.DataContext).State = ListenerState.Listening;
}如果要将视图与视图模型完全分离,可以在控件中为状态创建依赖属性:
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); }
}然后,在Loaded处理程序中设置该属性,而不是引用视图模型:
private void OnLoaded(object sender, RoutedEventArgs e)
{
this.ListenerState = ListenerState.Listening;
}最后,将属性绑定到标记中的视图模型的属性:
<local:YourControl ListenerState="{Binding State, Mode=TwoWay}" />https://stackoverflow.com/questions/3925141
复制相似问题