WPF - 使用运行新线程的MVVF命令关闭窗口

时间:2014-07-07 19:18:58

标签: c# wpf multithreading mvvm

设置

我有一个窗口和一个视图模型。 viewmodel有一个执行Task的命令。任务完成后,我希望效果为窗口关闭。

最可接受的(最佳实践)方式是什么?

我倾向于认为Dispatcher.Invoke是hacky和bad,但这是一个没有实际意义的因素,因为viewmodel没有对窗口或其调度程序的引用。

编辑:为了澄清,该窗口属于UI线程。该命令本身调用一个包装器来执行异步http请求(返回一个任务)。该命令可以附加一个ContinueWith。

我不想将视图模型紧密地耦合到视图(例如通过将窗口传递给视图模型)

public class Api 
{
    Task MakeHttpCall();
}

public class ViewModel, DependencyObject
{
    private Api _api;

    public Task DoHttpCall() { return _api.MakeHttpCall(); }
    public MyCommand MyCommandInst { get; private set; }
}

public class MyCommand : ICommand
{
    void Execute(object parameter)
    {
       var viewModel = GetViewModel(parameter);
       viewModel.DoHttpCall().ContinueWith( t => HandleCompletionAndSomehowTriggerWindowClose(t));
    }
}

然后是view.xaml:     <Button Command={Binding MyCommandInst} CommandParameter={Binding}>Do Stuff</Button>

2 个答案:

答案 0 :(得分:1)

我使用MVVM Light来帮助推动这一过程。 ViewModel没有引用View,它只是发布要关闭的消息,并且View已注册以接收这些消息。

在我的观点背后的代码中,我订阅了这样的Messenger服务:

public class MyView
{
   public MyView()
   {
      InitializeComponent();
      Messenger.Default.Register<NotificationMessage>(this, msg =>
      {
         if ((msg.Sender == this.DataContext) && (msg.Notification.ToUpper() == "CLOSE"))
            this.Close();
      });
   }
}

然后在ViewModel中(在异步进程的回调方法中或在命令方法结束时,如果没有运行异步):

Messenger.Default.Send(new NotificationMessage(this, "Close"));

答案 1 :(得分:0)

通常,我认为,使用MVVM模式关闭窗口取决于在视图所订阅的视图模型上引发某种形式的Close事件:

public class MyView
{
    public MyView(MyViewModel viewModel)
    {
        this.DataContext = viewModel;
        viewModel.Close += (_, __) => Dispatcher.Invoke(this.Close);
    }
}

从任务的Close操作中提升ContinueWith事件,您就完成了。