使用MVVM实现"关闭窗口"命令

mca*_*lex 40 c# wpf mvvm relaycommand

所以我的第一次尝试完成了后面的代码,现在我正在尝试重构我的代码以使用MVVM模式,遵循MVVM 在框信息中的指导.

我已经创建了一个viewmodel类来匹配我的视图类,并且我将代码从代码中移出到viewmodel中,从命令开始.

我的第一个障碍是尝试实现一个"关闭"按钮,如果数据未被修改则关闭窗口.我已经装配了一个CloseCommand来替换'onClick'方法,除了代码试图运行的地方外,一切都很好this.Close().显然,由于代码已从窗口移动到普通类,因此'this'不是窗口,因此不可关闭.但是,根据MVVM,viewmodel不知道视图,所以我无法调用view.Close().

有人可以建议我如何从viewmodel命令关闭窗口?

ken*_*n2k 63

我个人使用一种非常简单的方法:对于与可关闭View相关的每个ViewModel,我创建了一个基本ViewModel,如下例所示:

public abstract class CloseableViewModel
{
    public event EventHandler ClosingRequest;

    protected void OnClosingRequest()
    {
        if (this.ClosingRequest != null)
        {
            this.ClosingRequest(this, EventArgs.Empty);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在继承自的ViewModel中CloseableViewModel,只需调用this.OnClosingRequest();Close命令即可.

在视图中:

public class YourView
{
    ...
    var vm = new ClosableViewModel();
    this.Datacontext = vm;
    vm.ClosingRequest += (sender, e) => this.Close();
}
Run Code Online (Sandbox Code Playgroud)


Roh*_*ats 30

您无需将View实例传递给ViewModel层.您可以像这样访问主窗口 -

Application.Current.MainWindow.Close()
Run Code Online (Sandbox Code Playgroud)

我发现在ViewModel类中访问主窗口没有问题,如上所述.根据MVVM原则,View和ViewModel之间不应该存在紧密耦合,即它们应该忽略其他操作.在这里,我们没有从View向ViewModel传递任何内容.如果您想查找其他选项,这可能会对您有所帮助 - 使用MVVM关闭窗口

  • @Rohit:你以这种方式将你的viewmodel耦合到WPF.(申请类) (13认同)
  • @RohitVats这是违反MVVM的.拆分视图和ViewModels带来了可移植性:我可以实现控制台应用程序,后台进程,SilverLight网站,移动应用程序,使所有ViewModel保持不变,仅更改视图.因此,在ViewModel上调用类似"MainWindow"的内容是完全错误的.在后台进程中,"关闭主窗口"是什么意思?或者在测试用例套件中?如果要关闭的窗口不是主要的?在不违反MVVM的情况下处理这些问题的最佳方法是通过接口在ViewModels的属性中注入View实例 (6认同)
  • 我喜欢这个,但是viewmodel和允许/批准的应用程序之间是否有耦合? (4认同)
  • 耦合是指您使用实例变量跨层传递数据,但在此处您正在访问应用程序的静态属性以获取窗口.对我来说,它不违反任何MVVM规则. (3认同)

小智 26

我点击按钮时从视图模型关闭窗口的解决方案如下:

在视图模型中

public RelayCommand CloseWindow;
Constructor()
{
    CloseWindow = new RelayCommand(CloseWin);
}

public void CloseWin(object obj)
{
    Window win = obj as Window;
    win.Close();
}
Run Code Online (Sandbox Code Playgroud)

在"视图"中,设置如下

<Button Command="{Binding CloseWindowCommand}" CommandParameter="{Binding ElementName=WindowNameTobeClose}" Content="Cancel" />
Run Code Online (Sandbox Code Playgroud)

  • 你不是让视图模型知道视图(`Window`)吗? (6认同)

HB *_*AAM 13

我是通过创建一个名为DialogResult的附加属性来实现的:

public static class DialogCloser
{
    public static readonly DependencyProperty DialogResultProperty =
        DependencyProperty.RegisterAttached(
            "DialogResult",
            typeof(bool?),
            typeof(DialogCloser),
            new PropertyMetadata(DialogResultChanged));

    private static void DialogResultChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var window = d as Window;
        if (window != null && (bool?)e.NewValue == true) 
                window.Close();
    }

    public static void SetDialogResult(Window target, bool? value)
    {
        target.SetValue(DialogResultProperty, value);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在窗口标记中将此内容写入XAML

WindowActions:DialogCloser.DialogResult="{Binding Close}"
Run Code Online (Sandbox Code Playgroud)

终于在ViewModel中了

    private bool _close;
    public bool Close
    {
        get { return _close; }
        set
        {
            if (_close == value)
                return;
            _close = value;
            NotifyPropertyChanged("Close");
        }
    }
Run Code Online (Sandbox Code Playgroud)

如果将Close更改为true,则窗口将关闭

Close = True;
Run Code Online (Sandbox Code Playgroud)


Kri*_*hna 6

这是最简单的解决方案和纯MVVM解决方案

ViewModel代码

public class ViewModel
{
    public Action CloseAction { get; set; }

    private void CloseCommandFunction()
    {
        CloseAction();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是XAML View Code

public partial class DialogWindow : Window
{
    public DialogWindow()
    {
        ViewModel vm = new ViewModel();
        this.DataContext = vm;

        vm.CloseAction = new Action(() => this.Close());
    }
}
Run Code Online (Sandbox Code Playgroud)


eol*_*dre 5

该解决方案快速简便.缺点是层之间存在一些耦合.

在您的viewmodel中:

public class MyWindowViewModel: ViewModelBase
{


    public Command.StandardCommand CloseCommand
    {
        get
        {
            return new Command.StandardCommand(Close);
        }
    }
    public void Close()
    {
        foreach (System.Windows.Window window in System.Windows.Application.Current.Windows)
        {
            if (window.DataContext == this)
            {
                window.Close();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)