C# 使用 MVVM 实现“关闭窗口”命令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11945821/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 19:48:13  来源:igfitidea点击:

Implementing "close window" command with MVVM

c#wpfmvvmrelaycommand

提问by mcalex

So my first attempt did everything out of the code behind, and now I'm trying to refactor my code to use the MVVM pattern, following the guidance of the MVVM in the boxinformation.

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

I've created a viewmodel class to match my view class, and I'm moving the code out of the code behind into the viewmodel starting with the commands.

我已经创建了一个视图模型类来匹配我的视图类,并且我正在将代码从后面的代码中移到视图模型中,并从命令开始。

My first snag is trying to implement a 'Close' button that closes the window if the data has not been modified. I've rigged up a CloseCommand to replace the 'onClick' method and all is good except for where the code tries to run this.Close(). Obviously, since the code has been moved from a window to a normal class, 'this' isn't a window and therefore isn't closeable. However, according to MVVM, the viewmodel doesn't know about the view, so i can't call view.Close().

我的第一个障碍是尝试实现一个“关闭”按钮,如果数据未被修改,该按钮将关闭窗口。我已经设置了一个 CloseCommand 来替换 'onClick' 方法,除了代码试图运行的地方之外,一切都很好this.Close()。显然,由于代码已从窗口移至普通类,因此“this”不是窗口,因此不可关闭。但是,根据 MVVM,视图模型不知道视图,因此我无法调用view.Close().

Can someone suggest how I can close the window from the viewmodel command?

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

采纳答案by Rohit Vats

You don't need to pass the View instance to your ViewModel layer. You can access the main window like this -

您不需要将 View 实例传递给您的 ViewModel 层。您可以像这样访问主窗口 -

Application.Current.MainWindow.Close()

I see no issue in accessing your main window in ViewModel class as stated above. As per MVVM principle there should not be tight coupling between your View and ViewModel i.e. they should work be oblivious of others operation. Here, we are not passing anything to ViewModel from View. If you want to look for other options this might help you - Close window using MVVM

如上所述,我认为在 ViewModel 类中访问主窗口没有问题。根据 MVVM 原则,您的 View 和 ViewModel 之间不应紧密耦合,即它们应该在工作时忽略其他操作。在这里,我们没有从 View 向 ViewModel 传递任何东西。如果您想寻找其他选项,这可能对您有所帮助 -使用 MVVM 关闭窗口

回答by HB MAAM

I do it by creating a attached property called DialogResult:

我通过创建一个名为 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);
    }
}

then write this to you XAML, in the window tag

然后在窗口标记中将其写入 XAML

WindowActions:DialogCloser.DialogResult="{Binding Close}"

finally in the ViewModel

最后在 ViewModel

    private bool _close;
    public bool Close
    {
        get { return _close; }
        set
        {
            if (_close == value)
                return;
            _close = value;
            NotifyPropertyChanged("Close");
        }
    }

if you change the Close to true, the window will be closed

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

Close = True;

回答by ken2k

I personally use a very simple approach: for every ViewModel that is related to a closeable View, I created a base ViewModel like this following example:

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

public abstract class CloseableViewModel
{
    public event EventHandler ClosingRequest;

    protected void OnClosingRequest()
    {
        if (this.ClosingRequest != null)
        {
            this.ClosingRequest(this, EventArgs.Empty);
        }
    }
}

Then in your ViewModel that inherits from CloseableViewModel, simply call this.OnClosingRequest();for the Closecommand.

然后在您的视图模型,从继承CloseableViewModel,只需调用this.OnClosingRequest();Close命令。

In the view:

在视图中:

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

回答by PRASAD CP

My solution to close a window from view model while clicking a button is as follows:

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

In view model

在视图模型中

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

public void CloseWin(object obj)
{
    Window win = obj as Window;
    win.Close();
}

In View, set as follows

在View中,设置如下

<Button Command="{Binding CloseWindowCommand}" CommandParameter="{Binding ElementName=WindowNameTobeClose}" Content="Cancel" />

回答by eoldre

This solution is quick and easy. Downside is that there is some coupling between the layers.

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

In your 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();
            }
        }
    }
}

回答by Matt Winward

This is very similar to eoldre's answer. It's functionally the same in that it looks through the same Windows collection for a window that has the view model as its datacontext; but I've used a RelayCommand and some LINQ to achieve the same result.

这与 eoldre 的回答非常相似。它在功能上是相同的,因为它通过相同的 Windows 集合查找具有视图模型作为其数据上下文的窗口;但我使用了 RelayCommand 和一些 LINQ 来实现相同的结果。

public RelayCommand CloseCommand
{
    get
    {
        return new RelayCommand(() => Application.Current.Windows
            .Cast<Window>()
            .Single(w => w.DataContext == this)
            .Close());
    }
}

回答by Chris Amelinckx

This is taken from ken2k answer (thanks!), just adding the CloseCommandalso to the base CloseableViewModel.

这取自 ken2k 答案(谢谢!),只需将 the CloseCommandalso添加到 base CloseableViewModel

public class CloseableViewModel
{
    public CloseableViewModel()
    {
        CloseCommand = new RelayCommand(this.OnClosingRequest);
    }

    public event EventHandler ClosingRequest;

    protected void OnClosingRequest()
    {
        if (this.ClosingRequest != null)
        {
            this.ClosingRequest(this, EventArgs.Empty);
        }
    }

    public RelayCommand CloseCommand
    {
        get;
        private set;
    }
}

Your view model, inherits it

你的视图模型,继承它

public class MyViewModel : CloseableViewModel

Then on you view

然后在你查看

public MyView()
{
    var viewModel = new StudyDataStructureViewModel(studyId);
    this.DataContext = viewModel;

    //InitializeComponent(); ...

    viewModel.ClosingRequest += (sender, e) => this.Close();
}

回答by Anil8753

Given a way, Please check

给个方法,请检查

https://stackoverflow.com/a/30546407/3659387

https://stackoverflow.com/a/30546407/3659387

Short Description

简短的介绍

  1. Derive your ViewModel from INotifyPropertyChanged
  2. Create a observable property CloseDialog in ViewModel, Change CloseDialog property whenever you want to close the dialog.
  3. Attach a Handler in View for this property change
  4. Now you are almost done. In the event handler make DialogResult = true
  1. 从 INotifyPropertyChanged 派生您的 ViewModel
  2. 在 ViewModel 中创建一个 observable 属性 CloseDialog,每当您想关闭对话框时更改 CloseDialog 属性。
  3. 为此属性更改在视图中附加一个处理程序
  4. 现在你快完成了。在事件处理程序中使 DialogResult = true

回答by David Fawzy

using MVVM-light toolkit:

使用 MVVM-light 工具包:

In the ViewModel:

在视图模型中:

 public void notifyWindowToClose()
{
    Messenger.Default.Send<NotificationMessage>(
        new NotificationMessage(this, "CloseWindowsBoundToMe")
    );
}

And in the View:

在视图中:

 Messenger.Default.Register<NotificationMessage>(this, (nm) =>
{
    if (nm.Notification == "CloseWindowsBoundToMe")
    {
        if (nm.Sender == this.DataContext)
            this.Close();
    }
});

回答by Eric Bole-Feysot

MVVM-light with a custom message notification to avoid the window to process every notificationmessage

带有自定义消息通知的 MVVM-light 避免窗口处理每个通知消息

In the viewmodel:

在视图模型中:

public class CloseDialogMessage : NotificationMessage
{
    public CloseDialogMessage(object sender) : base(sender, "") { }
}

private void OnClose()
{
    Messenger.Default.Send(new CloseDialogMessage(this));
}

Register the message in the window constructor:

在窗口构造函数中注册消息:

Messenger.Default.Register<CloseDialogMessage>(this, nm =>
{
    Close();
});