从ViewModel中关闭窗口

本文关键字:窗口 ViewModel | 更新日期: 2023-09-27 18:10:36

我使用window control创建一个登录,允许用户登录到我正在创建的WPF应用程序。

到目前为止,我已经创建了一个方法来检查用户是否在登录屏幕上的textboxbindingproperties中为usernamepassword输入了正确的凭据。

我通过创建bool方法实现了这一点,如下所示;

public bool CheckLogin()
{
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();
    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome " + user.Username + ", you have successfully logged in.");
        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
}
public ICommand ShowLoginCommand
{
    get
    {
        if (this.showLoginCommand == null)
        {
            this.showLoginCommand = new RelayCommand(this.LoginExecute, null);
        }
        return this.showLoginCommand;
    }
}
private void LoginExecute()
{
    this.CheckLogin();
} 

我也有一个command,我bind到我的按钮在xaml像这样;

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" />

当我输入用户名和密码时,它执行适当的代码,无论它是正确的,还是错误的。但是,当用户名和密码都正确时,我如何从ViewModel关闭此窗口?

我以前尝试过使用dialog modal,但它没有完全奏效。此外,在我的app.xaml中,我做了如下操作,首先加载登录页面,一旦为true,就加载实际的应用程序。

private void ApplicationStart(object sender, StartupEventArgs e)
{
    Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
    var dialog = new UserView();
    if (dialog.ShowDialog() == true)
    {
        var mainWindow = new MainWindow();
        Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
        Current.MainWindow = mainWindow;
        mainWindow.Show();
    }
    else
    {
        MessageBox.Show("Unable to load application.", "Error", MessageBoxButton.OK);
        Current.Shutdown(-1);
    }
}

问题:如何从ViewModel关闭登录Window control ?

提前感谢。

从ViewModel中关闭窗口

您可以使用CommandParameter将窗口传递给ViewModel。

我已经实现了一个CloseWindow方法,它以Windows为参数并关闭它。窗口通过CommandParameter传递给ViewModel。注意,您需要为应该关闭的窗口定义一个x:Name。在我的XAML窗口中,我通过Command调用这个方法,并通过CommandParameter将窗口本身作为参数传递给ViewModel。

Command="{Binding CloseWindowCommand, Mode=OneWay}" 
CommandParameter="{Binding ElementName=TestWindow}"

ViewModel

public RelayCommand<Window> CloseWindowCommand { get; private set; }
public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
}
private void CloseWindow(Window window)
{
    if (window != null)
    {
       window.Close();
    }
}
<<p> 视图/em>
<Window x:Class="ClientLibTestTool.ErrorView"
        x:Name="TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:localization="clr-namespace:ClientLibTestTool.ViewLanguages"
        DataContext="{Binding Main, Source={StaticResource Locator}}"
        Title="{x:Static localization:localization.HeaderErrorView}"
        Height="600" Width="800"
        ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen">
    <Grid> 
        <Button Content="{x:Static localization:localization.ButtonClose}" 
                Height="30" 
                Width="100" 
                Margin="0,0,10,10" 
                IsCancel="True" 
                VerticalAlignment="Bottom" 
                HorizontalAlignment="Right" 
                Command="{Binding CloseWindowCommand, Mode=OneWay}" 
                CommandParameter="{Binding ElementName=TestWindow}"/>
    </Grid>
</Window>

请注意,我使用的是MVVM轻型框架,但主体适用于每个wpf应用程序。

这个解决方案违反了MVVM模式,因为视图模型不应该知道任何关于UI实现的信息。如果你想严格遵循MVVM编程范例,你必须用接口抽象视图的类型。

MVVM一致性解决方案 (Former EDIT2)

用户Crono在注释部分提到了一个有效的点:

将Window对象传递给视图模型会破坏MVVM模式恕我直言,因为它迫使你的虚拟机知道它正在以什么方式被查看。

可以通过引入一个包含close方法的接口来修复这个问题。

接口:

public interface ICloseable
{
    void Close();
}

你重构的ViewModel看起来像这样:

ViewModel

public RelayCommand<ICloseable> CloseWindowCommand { get; private set; }
public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<IClosable>(this.CloseWindow);
}
private void CloseWindow(ICloseable window)
{
    if (window != null)
    {
        window.Close();
    }
}

你必须在视图中引用和实现ICloseable接口

View (Code behind)

public partial class MainWindow : Window, ICloseable
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

原问题的答案:(原EDIT1)

您的登录按钮(添加CommandParameter):

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" CommandParameter="{Binding ElementName=LoginWindow}"/>
代码:

 public RelayCommand<Window> CloseWindowCommand { get; private set; } // the <Window> is important for your solution!
 public MainViewModel() 
 {
     //initialize the CloseWindowCommand. Again, mind the <Window>
     //you don't have to do this in your constructor but it is good practice, thought
     this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
 }
 public bool CheckLogin(Window loginWindow) //Added loginWindow Parameter
 {
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();
    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome "+ user.Username + ", you have successfully logged in.");
        this.CloseWindow(loginWindow); //Added call to CloseWindow Method
        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
 }
 //Added CloseWindow Method
 private void CloseWindow(Window window)
 {
     if (window != null)
     {
         window.Close();
     }
 }

当我需要这样做时,我通常在视图模型上放置一个事件,然后在将视图模型绑定到窗口时将其连接到Window.Close()

public class LoginViewModel
{
    public event EventHandler OnRequestClose;
    private void Login()
    {
        // Login logic here
        OnRequestClose(this, new EventArgs());
    }
}

创建登录窗口时

var vm = new LoginViewModel();
var loginWindow = new LoginWindow
{
    DataContext = vm
};
vm.OnRequestClose += (s, e) => loginWindow.Close();
loginWindow.ShowDialog(); 

留在MVVM,我认为使用混合SDK (System.Windows.Interactivity)的行为或Prism的自定义交互请求可以很好地解决这种情况。

如果选择Behavior路线,大致思路如下:

public class CloseWindowBehavior : Behavior<Window>
{
    public bool CloseTrigger
    {
        get { return (bool)GetValue(CloseTriggerProperty); }
        set { SetValue(CloseTriggerProperty, value); }
    }
    public static readonly DependencyProperty CloseTriggerProperty =
        DependencyProperty.Register("CloseTrigger", typeof(bool), typeof(CloseWindowBehavior), new PropertyMetadata(false, OnCloseTriggerChanged));
    private static void OnCloseTriggerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behavior = d as CloseWindowBehavior;
        if (behavior != null)
        {
            behavior.OnCloseTriggerChanged();
        }
    }
    private void OnCloseTriggerChanged()
    {
        // when closetrigger is true, close the window
        if (this.CloseTrigger)
        {
            this.AssociatedObject.Close();
        }
    }
}

然后在你的窗口中,你只需将CloseTrigger绑定到一个布尔值,该值将在你想要关闭窗口时设置。

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:local="clr-namespace:TestApp"
        Title="MainWindow" Height="350" Width="525">
    <i:Interaction.Behaviors>
        <local:CloseWindowBehavior CloseTrigger="{Binding CloseTrigger}" />
    </i:Interaction.Behaviors>
    <Grid>
    </Grid>
</Window>

最后,你的DataContext/ViewModel将有一个属性,当你想要关闭窗口时,你可以这样设置:

public class MainWindowViewModel : INotifyPropertyChanged
{
    private bool closeTrigger;
    /// <summary>
    /// Gets or Sets if the main window should be closed
    /// </summary>
    public bool CloseTrigger
    {
        get { return this.closeTrigger; }
        set
        {
            this.closeTrigger = value;
            RaisePropertyChanged(nameof(CloseTrigger));
        }
    }
    public MainWindowViewModel()
    {
        // just setting for example, close the window
        CloseTrigger = true;
    }
    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

设置您的窗口。DataContext = new MainWindowViewModel())

可能晚了,但这是我的答案

foreach (Window item in Application.Current.Windows)
{
    if (item.DataContext == this) item.Close();
}

这是我在几个项目中使用的东西。它可能看起来像一个hack,但它工作得很好。

public class AttachedProperties : DependencyObject //adds a bindable DialogResult to window
{
    public static readonly DependencyProperty DialogResultProperty = 
        DependencyProperty.RegisterAttached("DialogResult", typeof(bool?), typeof(AttachedProperties), 
        new PropertyMetaData(default(bool?), OnDialogResultChanged));
    public bool? DialogResult
    {
        get { return (bool?)GetValue(DialogResultProperty); }
        set { SetValue(DialogResultProperty, value); }
    }
    private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var window = d as Window;
        if (window == null)
            return;
        window.DialogResult = (bool?)e.NewValue;
    }
}

现在可以将DialogResult绑定到虚拟机并设置其属性值。当设置该值时,Window将关闭。

<!-- Assuming that the VM is bound to the DataContext and the bound VM has a property DialogResult -->
<Window someNs:AttachedProperties.DialogResult={Binding DialogResult} />

这是在我们的生产环境中运行的一个抽象

<Window x:Class="AC.Frontend.Controls.DialogControl.Dialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:DialogControl="clr-namespace:AC.Frontend.Controls.DialogControl" 
        xmlns:hlp="clr-namespace:AC.Frontend.Helper"
        MinHeight="150" MinWidth="300" ResizeMode="NoResize" SizeToContent="WidthAndHeight"
        WindowStartupLocation="CenterScreen" Title="{Binding Title}"
        hlp:AttachedProperties.DialogResult="{Binding DialogResult}" WindowStyle="ToolWindow" ShowInTaskbar="True"
        Language="{Binding UiCulture, Source={StaticResource Strings}}">
        <!-- A lot more stuff here -->
</Window>

可以看到,我先声明名称空间xmlns:hlp="clr-namespace:AC.Frontend.Helper",然后声明绑定hlp:AttachedProperties.DialogResult="{Binding DialogResult}"

AttachedProperty看起来像这样。这和我昨天发的不一样,但依我之见,应该不会有什么影响。

public class AttachedProperties
{
    #region DialogResult
    public static readonly DependencyProperty DialogResultProperty =
        DependencyProperty.RegisterAttached("DialogResult", typeof (bool?), typeof (AttachedProperties), new PropertyMetadata(default(bool?), OnDialogResultChanged));
    private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var wnd = d as Window;
        if (wnd == null)
            return;
        wnd.DialogResult = (bool?) e.NewValue;
    }
    public static bool? GetDialogResult(DependencyObject dp)
    {
        if (dp == null) throw new ArgumentNullException("dp");
        return (bool?)dp.GetValue(DialogResultProperty);
    }
    public static void SetDialogResult(DependencyObject dp, object value)
    {
        if (dp == null) throw new ArgumentNullException("dp");
        dp.SetValue(DialogResultProperty, value);
    }
    #endregion
}

简单的方法

public interface IRequireViewIdentification
{
    Guid ViewID { get; }
}

实现到ViewModel

public class MyViewVM : IRequireViewIdentification
{
    private Guid _viewId;
    public Guid ViewID
    {
        get { return _viewId; }
    }
    public MyViewVM()
    {
        _viewId = Guid.NewGuid();
    }
}

添加通用窗口管理器帮助器

public static class WindowManager
{
    public static void CloseWindow(Guid id)
    {
        foreach (Window window in Application.Current.Windows)
        {
            var w_id = window.DataContext as IRequireViewIdentification;
            if (w_id != null && w_id.ViewID.Equals(id))
            {
                window.Close();
            }
        }
    }
}
在viewmodel 中像这样关闭
WindowManager.CloseWindow(ViewID);

我知道这是一个旧的帖子,可能没有人会滚动到这里,我知道我没有。所以,在尝试了几个小时不同的东西之后,我发现了这个博客,那家伙就杀了它。这是最简单的方法,我试过了,效果很好。

博客

在ViewModel中:

...
public bool CanClose { get; set; }
private RelayCommand closeCommand;
public ICommand CloseCommand
{
    get
    {
        if(closeCommand == null)
        (
            closeCommand = new RelayCommand(param => Close(), param => CanClose);
        )
    }
}
public void Close()
{
    this.Close();
}
...

向ViewModel添加一个Action属性,但是从View的代码隐藏文件中定义它。这将允许我们动态地在ViewModel上定义一个指向View的引用。

在ViewModel上,我们只需添加:

public Action CloseAction { get; set; }

在View中,我们将其定义为:

public View()
{
    InitializeComponent() // this draws the View
    ViewModel vm = new ViewModel(); // this creates an instance of the ViewModel
    this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
    if ( vm.CloseAction == null )
        vm.CloseAction = new Action(() => this.Close());
}

这是一个使用MVVM Light Messenger而不是事件的简单示例。当按钮被点击时,视图模型发送一个关闭消息:

    public MainViewModel()
    {
        QuitCommand = new RelayCommand(ExecuteQuitCommand);
    }
    public RelayCommand QuitCommand { get; private set; }
    private void ExecuteQuitCommand() 
    {
        Messenger.Default.Send<CloseMessage>(new CloseMessage());
    }

然后在窗口后面的代码中接收。

    public Main()
    {   
        InitializeComponent();
        Messenger.Default.Register<CloseMessage>(this, HandleCloseMessage);
    }
    private void HandleCloseMessage(CloseMessage closeMessage)
    {
        Close();
    }

这个怎么样?

ViewModel:

class ViewModel
{
    public Action CloseAction { get; set; }
    private void Stuff()
    {
       // Do Stuff
       CloseAction(); // closes the window
    }
}

在你的ViewModel中使用CloseAction()来关闭窗口,就像上面的例子一样。

视图:

public View()
{
    InitializeComponent();
    ViewModel vm = new ViewModel (); // this creates an instance of the ViewModel
    this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
    if (vm.CloseAction == null)
        vm.CloseAction = new Action(() => this.Close());
}

您可以像这样在ViewModel中创建新的事件处理程序。

public event EventHandler RequestClose;
    protected void OnRequestClose()
    {
        if (RequestClose != null)
            RequestClose(this, EventArgs.Empty);
    }

然后为ExitCommand定义RelayCommand

private RelayCommand _CloseCommand;
    public ICommand CloseCommand
    {
        get
        {
            if(this._CloseCommand==null)
                this._CloseCommand=new RelayCommand(CloseClick);
            return this._CloseCommand;
        }
    }
    private void CloseClick(object obj)
    {
        OnRequestClose();
    }

Then In XAML file set

<Button Command="{Binding CloseCommand}" />

在xaml.cs文件中设置DataContext并订阅我们创建的事件。

public partial class MainWindow : Window
{
    private ViewModel mainViewModel = null;
    public MainWindow()
    {
        InitializeComponent();
        mainViewModel = new ViewModel();
        this.DataContext = mainViewModel;
        mainViewModel.RequestClose += delegate(object sender, EventArgs args) { this.Close(); };
    }
}

我提供的方法是在ViewModel中声明事件并使用下面的blend InvokeMethodAction

样本ViewModel

public class MainWindowViewModel : BindableBase, ICloseable
{
    public DelegateCommand SomeCommand { get; private set; }
    #region ICloseable Implementation
    public event EventHandler CloseRequested;        
    public void RaiseCloseNotification()
    {
        var handler = CloseRequested;
        if (handler != null)
        {
            handler.Invoke(this, EventArgs.Empty);
        }
    }
    #endregion
    public MainWindowViewModel()
    {
        SomeCommand = new DelegateCommand(() =>
        {
            //when you decide to close window
            RaiseCloseNotification();
        });
    }
}

I关闭接口如下,但不需要执行此操作。ICloseable将有助于创建通用视图服务,所以如果你通过依赖注入来构建视图和ViewModel,那么你可以做的是

internal interface ICloseable
{
    event EventHandler CloseRequested;
}

使用ICloseable

var viewModel = new MainWindowViewModel();
        // As service is generic and don't know whether it can request close event
        var window = new Window() { Content = new MainView() };
        var closeable = viewModel as ICloseable;
        if (closeable != null)
        {
            closeable.CloseRequested += (s, e) => window.Close();
        }

下面是Xaml,你可以使用这个Xaml,即使你不实现接口,它只需要你的视图模型引发CloseRquested。

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFRx"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
xmlns:ViewModels="clr-namespace:WPFRx.ViewModels" x:Name="window" x:Class="WPFRx.MainWindow"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525" 
d:DataContext="{d:DesignInstance {x:Type ViewModels:MainWindowViewModel}}">
<i:Interaction.Triggers>
    <i:EventTrigger SourceObject="{Binding Mode=OneWay}" EventName="CloseRequested" >
        <ei:CallMethodAction TargetObject="{Binding ElementName=window}" MethodName="Close"/>
    </i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
    <Button Content="Some Content" Command="{Binding SomeCommand}" Width="100" Height="25"/>
</Grid>

您可以使用MVVMLight工具包中的Messenger。在您的ViewModel中发送这样的消息:
Messenger.Default.Send(new NotificationMessage("Close"));
然后在你的windows代码后面,在InitializeComponent之后,像这样注册该消息:

Messenger.Default.Register<NotificationMessage>(this, m=>{
    if(m.Notification == "Close") 
    {
        this.Close();
    }
   });

你可以在这里找到更多关于MVVMLight工具包的信息:Codeplex上的MVVMLight工具包

请注意,在MVVM中没有"完全没有代码滞后规则",您可以在视图代码滞后中注册消息。

您可以将窗口视为一个服务(例如:UI服务)并通过接口将自身传递给视图模型,如下:

public interface IMainWindowAccess
{
    void Close(bool result);
}
public class MainWindow : IMainWindowAccess
{
    // (...)
    public void Close(bool result)
    {
        DialogResult = result;
        Close();
    }
}
public class MainWindowViewModel
{
    private IMainWindowAccess access;
    public MainWindowViewModel(IMainWindowAccess access)
    {
        this.access = access;
    }
    public void DoClose()
    {
        access.Close(true);
    }
}

该解决方案具有将视图本身传递给viewmodel而没有破坏MVVM的缺点的大多数优点,因为尽管物理视图传递给viewmodel,后者仍然不知道前者,它只看到一些IMainWindowAccess。因此,例如,如果我们想将此解决方案迁移到其他平台,则只需为Activity适当地实现IMainWindowAccess即可。

我在这里发布解决方案,提出不同的方法比事件(虽然它实际上非常相似),因为它似乎比事件实现(附加/分离等)简单一点,但仍然与MVVM模式很好地对齐。

很简单。你可以为Login - LoginViewModel创建你自己的ViewModel类。你可以创建viewvar dialog = new UserView();在你的LoginViewModel中。你可以设置命令登录命令到按钮。

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding LoginCommand}" />

<Button Name="btnCancel" IsDefault="True" Content="Login" Command="{Binding CancelCommand}" />

ViewModel类:

public class LoginViewModel
{
    Window dialog;
    public bool ShowLogin()
    {
       dialog = new UserView();
       dialog.DataContext = this; // set up ViewModel into View
       if (dialog.ShowDialog() == true)
       {
         return true;
       }
       return false;
    }
    ICommand _loginCommand
    public ICommand LoginCommand
    {
        get
        {
            if (_loginCommand == null)
                _loginCommand = new RelayCommand(param => this.Login());
            return _loginCommand;
        }
    }
    public void CloseLoginView()
    {
            if (dialog != null)
          dialog.Close();
    }   
    public void Login()
    {
        if(CheckLogin()==true)
        {
            CloseLoginView();         
        }
        else
        {
          // write error message
        }
    }
    public bool CheckLogin()
    {
      // ... check login code
      return true;
    }
}

这是我做得很简单的一种方法:

YourWindow.xaml.cs

//In your constructor
public YourWindow()
{
    InitializeComponent();
    DataContext = new YourWindowViewModel(this);
}

YourWindowViewModel.cs

private YourWindow window;//so we can kill the window
//In your constructor
public YourWindowViewModel(YourWindow window)
{
    this.window = window;
}
//to close the window
public void CloseWindow()
{
    window.Close();
}

我看不出你选择的答案有什么错,我只是觉得这可能是一个更简单的方法!

在MVVM WPF中,我通常将视图设计为UserControl。这只是一个你想如何展示它的问题。如果你想让它在一个窗口中,那么你可以做一个WindowService类:

public class WindowService
{
   //...
   public void Show_window(object viewModel, int height, int width, string title)
   {
     var window = new Window
     {
       Content = viewModel,
       Title = title,
       Height = height,
       Width = width,
       WindowStartupLocation = WindowStartupLocation.CenterOwner,
       Owner = Application.Current.MainWindow,
       Style = (Style)Application.Current.FindResource("Window_style") //even style can be added
      };
      //If you own custom window style, then you can bind close/minimize/maxmize/restore buttons like this 
      window.CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, OnCloseWindow));
      window.CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, OnMaximizeWindow, OnCanResizeWindow));
      window.CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, OnMinimizeWindow, OnCanMinimizeWindow));
      window.CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, OnRestoreWindow, OnCanResizeWindow));
                  
      window.ShowDialog();
   }
   public void Close_window(object viewmodel)
   {
       //Close window
       foreach (Window item in Application.Current.Windows)
       {
          if (item.Content == viewmodel) item.Close();
       }
    }
}

使用我的方法很简单。通常你想要关闭窗口时,它发生了一些事情。所以,当它这样做的时候,只是从相应的ViewModel调用Close_window方法-那个是在窗口中显示的UserControl的DataContext。看下面的例子:

1)。我们从某个Viewmodel打开窗口:

public class MyViewModel // ViewModel where you open window
{
   private readonly WindowService _windowservice // or inject/inherit from Base
   public MyViewModel()
   {
     _windowservice = new WindowService();
   }  
   private void Example_method()
   {
        //...Open window
        _windowservice.Show_window(new WindowViewModel(),100,100,"Test window");
   }
  
}

2)。我们的窗口已经打开,现在我们想要关闭它:

 public class WindowViewModel // ViewModel which is your Window content!
 {
     private readonly WindowService _windowservice // or inject/inherit from Base
     public MyViewModel()
     {
       _windowservice = new WindowService();
     }  
     private void Example_method()
     {
          //Close window
          _windowservice.Close(this); //Pass a reference of viewmodel to method
     }
    
  }

这个解决方案远没有其他公认的答案那么优雅,但对我来说它是有效的。我在项目中广泛使用它,到目前为止还没有问题。但我肯定有人会说"这违反了MVVM原则"。

您可以使用以下代码关闭当前窗口:

Application.Current.Windows[0].Close();

System.Environment.Exit(0);