C# 实施";“关闭窗口”;使用MVVM的命令

C# 实施";“关闭窗口”;使用MVVM的命令,c#,wpf,mvvm,relaycommand,C#,Wpf,Mvvm,Relaycommand,因此,我的第一次尝试完全脱离了代码,现在我正试图按照MVVM信息的指导,重构代码以使用MVVM模式 我已经创建了一个viewmodel类来匹配我的view类,并且从命令开始将代码从代码中移到viewmodel中 我的第一个障碍是试图实现一个“关闭”按钮,如果数据没有被修改,它会关闭窗口。我已经装配了一个CloseCommand来替换“onClick”方法,除了代码尝试运行this.Close()之外,一切都很好。显然,由于代码已从窗口移动到普通类,“this”不是窗口,因此不可关闭。但是,根据M

因此,我的第一次尝试完全脱离了代码,现在我正试图按照MVVM信息的指导,重构代码以使用MVVM模式

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

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


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

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

公共静态类对话框关闭器
{
公共静态只读从属属性对话框ResultProperty=
DependencyProperty.RegisterAttached(
“DialogResult”,
类型(bool?),
类型(对话框闭合器),
新属性元数据(DialogResultChanged));
私有静态无效对话框ResultChanged(
依赖对象d,
DependencyPropertyChangedEventArgs(附件e)
{
var窗口=d作为窗口;
if(window!=null&(bool?)e.NewValue==true)
window.Close();
}
公共静态无效SetDialogResult(窗口目标,布尔值)
{
SetValue(DialogResultProperty,value);
}
}
然后在窗口标记中,将此内容写入XAML

WindowActions:DialogCloser.DialogResult="{Binding Close}"
最后在ViewModel中

private bool\u close;
公共厕所关闭
{
获取{return\u close;}
设置
{
如果(_close==值)
返回;
_关闭=值;
NotifyPropertyChanged(“关闭”);
}
}
如果将“关闭”更改为“真”,则窗口将关闭

Close = True;

不需要将视图实例传递到ViewModel图层。您可以像这样访问主窗口-

Application.Current.MainWindow.Close()

如上所述,我认为在ViewModel类中访问主窗口没有问题。根据MVVM原则,您的视图和ViewModel之间不应存在紧密耦合,即它们应在不考虑其他操作的情况下工作。这里,我们不从视图向ViewModel传递任何内容。如果您想寻找其他选项,这可能会对您有所帮助-

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

公共抽象类CloseableViewModel
{
公共事件处理程序关闭请求;
受保护的void OnClosingRequest()
{
if(this.ClosingRequest!=null)
{
this.ClosingRequest(this,EventArgs.Empty);
}
}
}
然后在继承自
CloseableViewModel
的ViewModel中,只需调用
this.OnClosingRequest()用于
关闭
命令

他认为:

公共类视图
{
...
var vm=新的ClosableViewModel();
this.Datacontext=vm;
vm.ClosingRequest+=(发送方,e)=>this.Close();
}

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

视图模型

private ICommand _cancelCommand;        
public ICommand CancelCommand       
{
   get          
     {
        if (_cancelCommand == null)
           {
              _cancelCommand = new DelegateCommand<Window>(
                    x =>
                    {
                        x?.Close();
                    });
            }

            return _cancelCommand;          
     }      
}
公共中继命令关闭窗口;
构造函数()
{
CloseWindow=新的中继命令(CloseWin);
}
公共无效关闭窗口(对象obj)
{
win窗口=obj作为窗口;
win.Close();
}
在视图中,设置如下


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

在viewmodel中:

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

private void OnClose()
{
    Messenger.Default.Send(new CloseDialogMessage(this));
}
公共类MyWindowViewModel:ViewModelBase { public命令。标准命令CloseCommand { 得到 { 返回新命令。标准命令(关闭); } } 公众假期结束() { foreach(System.Windows.Application.Current.Windows中的System.Windows.Window窗口) { if(window.DataContext==此) { window.Close(); } } } }
这与eoldre的答案非常相似。它在功能上是相同的,因为它通过相同的Windows集合查找具有视图模型作为其datacontext的窗口;但是我使用了一个RelayCommand和一些LINQ来实现相同的结果

public RelayCommand CloseCommand
{
    get
    {
        return new RelayCommand(() => Application.Current.Windows
            .Cast<Window>()
            .Single(w => w.DataContext == this)
            .Close());
    }
}
public RelayCommand close命令
{
得到
{
返回新的RelayCommand(()=>Application.Current.Windows
.Cast()
.Single(w=>w.DataContext==this)
.Close());
}
}

这是来自ken2k的答案(谢谢!),只需将
CloseCommand
也添加到基础
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;
    }
}
您的视图模型将继承它

public class MyViewModel : CloseableViewModel
那么在你看来

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

    //InitializeComponent(); ...

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

请给我一条路

简短描述

  • 从INotifyPropertyChanged派生ViewModel
  • 在ViewModel中创建可观察属性CloseDialog,在需要关闭对话框时更改CloseDialog属性
  • 为此属性更改在视图中附加处理程序
  • 现在你差不多完成了。在事件处理程序中,使DialogResult=true

  • 使用MVVM light toolkit:

    在ViewModel中:

     public void notifyWindowToClose()
    {
        Messenger.Default.Send<NotificationMessage>(
            new NotificationMessage(this, "CloseWindowsBoundToMe")
        );
    }
    
    public void notifyWindowToClose()
    {
    Messenger.Default.Send(
    新通知消息(此“CloseWindowsBoundToMe”)
    );
    }
    
    并且认为:

     Messenger.Default.Register<NotificationMessage>(this, (nm) =>
    {
        if (nm.Notification == "CloseWindowsBoundToMe")
        {
            if (nm.Sender == this.DataContext)
                this.Close();
        }
    });
    
    Messenger.Default.Register(此,(nm)=>
    {
    如果(nm.Notification==“CloseWindowsBoundToMe”)
    {
    if(nm.Sender==this.DataContext)
    这个。关闭();
    }
    });
    
    MVVM灯带有自定义消息通知,以避免窗口处理每个通知消息

    在视图模式下
    public class ViewModel
    {
        public Action CloseAction { get; set; }
    
        private void CloseCommandFunction()
        {
            CloseAction();
        }
    }
    
    public partial class DialogWindow : Window
    {
        public DialogWindow()
        {
            ViewModel vm = new ViewModel();
            this.DataContext = vm;
    
            vm.CloseAction = new Action(() => this.Close());
        }
    }
    
    x:Name="AboutViewWindow"
    
    CommandParameter="{Binding ElementName=AboutViewWindow}"
    Command="{Binding CancelCommand}"
    
    private ICommand _cancelCommand;        
    public ICommand CancelCommand       
    {
       get          
         {
            if (_cancelCommand == null)
               {
                  _cancelCommand = new DelegateCommand<Window>(
                        x =>
                        {
                            x?.Close();
                        });
                }
    
                return _cancelCommand;          
         }      
    }