Prism2/MVVM:从ViewModel关闭View

5

如何从ViewModel中关闭View?

我有一个WPF窗口,其中定义了多个区域,并被用作我的应用程序的Shell来托管视图。我想让一个View能够从区域中删除自己,或者从选项卡容器中关闭它。我该如何从ViewModel实现这种行为?


在得到成员宝贵的评论后,我已成功编写了这个程序。实现这个样例类的代码已作为回答发布在本问题中。 - Raj
3个回答

7

由于您的ViewModel没有(也不应该)引用View,因此您无法直接关闭它。但是,您可以在ViewModel中添加一个Event来指示它希望关闭。

Josh Smith撰写了一篇文章,介绍如何实现这一点(在文章的中途左右)。


1
嗨,谢谢。我已经看过了。但是Josh的文章没有使用CompositeWPF,所以我想知道如何将这样的事件处理程序与Composite WPF的区域和引导程序相结合实现。 - Raj
1
你需要拿那段代码,将处理程序从window.Close() 改为 regionMananger.Regions["MyRegion"].Remove(window)。 - Anderson Imes
@Anderson,针对您之前的评论,我不太明白,在哪里调用regionManager.Regions[] ...?是在视图的代码后台吗? - Shimmy Weitzhandler
1
@Shimmy:这真的取决于情况。如果您有一个引用该区域中对象的视图,可能是从代码后台,但如果您在ViewModel中引用了该视图(有些人会这样做),那么它可能在ViewModel中。如果ViewModel在Region中,并且您只是在视图中进行数据模板化,则可以仅从ViewModel执行所有操作并使用.Remove(this)。这只取决于您的情况。 - Anderson Imes

5
这真的取决于您的应用程序架构,但以下是我使用Prism的方法。
首先,我想说,只要VM不是View的具体实现(即通过接口引用),它引用View就没问题。
我使用依赖注入将View和ViewModel结合在一起,非常类似于StockTraderRI中的做法。因此,我有一个IView和一个IViewModel。IViewModel有一个名为“View”的属性,类型为IView。
从代码层面(对我来说,通常是控制器...请参见StockTraderRI)开始使用区域,添加从区域中删除视图的机制。
例如:
myRegion.Remove(myIViewModel.View);

如果区域由控制器处理,您可能希望在VM上放置一个简单的事件,以便在VM想要“关闭”时通知。如果您希望使用弱事件模型,则也可以尝试使用IEventAggregator进行实验。如果区域在VM中处理,请在那里添加该代码。

谢谢。我觉得我懂逻辑了。但是我卡在了从模块解析控制器接口的地方。我得到了堆栈溢出异常。LoginController controller = this.container.Resolve<ILoginController>(); 抛出了一个错误。有什么建议吗? - Raj
看起来你的 Unity 容器存在一些循环依赖和/或配置不正确的问题。我建议你检查所有构造函数,确保每个注入的参数都是正确的。如果可以,请尝试粘贴容器设置代码以及几个类的构造函数。 - Jeremiah Morrill
嗨,请检查我在回答中粘贴的代码。再次感谢。 - Raj
你的建议很有用。我的View构造函数参数设置错误,导致了堆栈溢出异常。我已经修复了这些问题,现在它可以正常工作了。 - Raj

4
这是我的登录模块的样子:
    public class LoginModule : IModule
{
    private readonly IUnityContainer container;

    public LoginModule(IUnityContainer container)
    {
        this.container = container;
    }

    #region IModule Members

    public void Initialize()
    {
        this.container.RegisterType<ILoginController, LoginController>(new ContainerControlledLifetimeManager());
        this.container.RegisterType<ILoginView, LoginView>();
        this.container.RegisterType<ILoginViewModel, LoginViewModel>();

        ILoginController controller = this.container.Resolve<ILoginController>();
        controller.Run();
    }

    #endregion
}

这是控制器:

    public class LoginController : ILoginController
{
    private readonly IRegionManager regionManager;
    private readonly ILoginViewModel model;

    public LoginController(IRegionManager regionManager, ILoginViewModel model)
    {
        this.regionManager = regionManager;
        this.model = model;
        model.RequestClose += new EventHandler(model_RequestClose);
    }

    void model_RequestClose(object sender, EventArgs e)
    {
        regionManager.Regions["LoginRegion"].Remove(model.View);
    }

    #region ILoginController Members

    public void Run()
    {
        // Register views here
        regionManager.Regions["LoginRegion"].Add(model.view);
    }

    #endregion
}

这是我的视图模型(ViewModel):

    public class LoginViewModel : ViewModelBase, ILoginViewModel
{
    IEventAggregator _eventAggregator;
    RelayCommand _loginCommand;
    private readonly UserProfileRepository _userProfileRepository;
    public event EventHandler RequestClose;

    public ICommand LoginCommand
    {
        get
        {
            if (_loginCommand == null)
            {
                _loginCommand = new RelayCommand(
                    param => this.Login(),
                    param => this.IsValid());
            }
            return _loginCommand;
        }
    }

    public LoginViewModel(IEventAggregator eventAggregator, UserProfileRepository userProfileRepository, ILoginView view)
    {
        this._eventAggregator = eventAggregator;
        this._userProfileRepository = userProfileRepository;
        this.View = view;
    }

    #region ILoginViewModel Members

    public ILoginView View { get; private set; }

    #endregion
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接