从 ViewModel 关闭窗口

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

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

我通过创建 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();
}

I also have a command that I bind to my button within the xaml like so;

<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

先谢谢你。

146864 次浏览

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

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绑定到 VM 并设置其属性值。设置值时,Window将关闭。

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

This is an abstract of what's running in our production environment

<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
}

很简单。 您可以为 Login-LoginViewModel 创建自己的 ViewModel 类。 您可以在 LoginViewModel 中创建 viewvar 对话框 = new UserView () ;。 您可以将 Command LoginCommand 设置为按钮。

<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;
}
}

当我需要这样做时,我通常在视图模型上放置一个事件,然后在将视图模型绑定到窗口时将它挂接到 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();

Staying MVVM, I think using either Behaviors from the Blend SDK (System.Windows.Interactivity) or a custom interaction request from Prism could work really well for this sort of situation.

如果按照“行为”的路线,总体思路是这样的:

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

Then in your window, you would just bind the CloseTrigger to a boolean value that would be set when you wanted the window to close.

<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;
}

(设置 Window.DataContext = new MainWindowViewModel ())

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

我已经实现了一个 CloseWindow方法,它接受一个 Windows 作为参数并关闭它。窗口通过 CommandParameter传递给 ViewModel。注意,您需要为应该关闭的窗口定义一个 x:Name。在我的 XAML Window 中,我通过 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();
}
}

观景

<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 符合解决方案 (前 EDIT2)

用户 克罗诺在评论部分提到了一个有效的观点:

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

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

界面:

public interface ICloseable
{
void Close();
}

Your refactored ViewModel will look like this:

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

You have to reference and implement the ICloseable interface in your view

视图(后面的代码)

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

回答最初的问题: (前 EDIT1)

您的登录按钮(添加命令参数) :

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

System.Environment.Exit(0); in view model would work.

This is a way I did it pretty simply:

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

I don't see anything wrong with the answer you chose, I just thought this might be a more simple way to do it!

只需使用以下代码即可关闭当前窗口:

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

小菜一碟

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

然后像这样在视图模型中关闭它

WindowManager.CloseWindow(ViewID);

您可以像下面这样在 ViewModel 中创建新的 Event 处理程序。

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

然后在 XAML 文件集

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

将 xaml.cs 文件和 Subscribe 中的 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(); };
}
}

My proffered way is Declare event in ViewModel and use blend InvokeMethodAction as below.

视图模型示例

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 将有助于创建通用视图服务,所以如果你通过依赖注入构建视图和视图模型,那么你能做的就是

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,它只需要您的视图模型就可以引发 CloseQuest。

<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>

下面是一个使用 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();
}

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

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

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

注意,在 MVVM 中没有“根本没有代码隐藏规则”,您可以在视图代码隐藏中注册消息。

this呢?

视图模型:

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

也许很晚了,但这是我的答案

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

我知道这是一个老职位,可能没有人会滚动这么远,我知道我没有。所以,在尝试了几个小时不同的东西后,我发现了这个博客,这家伙把它删了。这是最简单的方法,试过了,效果非常好。

Blog

视图模型:

...


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; }

在《观点》中,我们会这样定义它:

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

您可以将窗口视为一个服务(例如 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,但是 viewmodel 仍然不知道前者,它只看到一些 IMainWindowAccess。因此,举例来说,如果我们想要将这个解决方案迁移到其他平台,那么只需要对 Activity适当地实现 IMainWindowAccess即可。

我在这里提出的解决方案提出了一个不同于事件的方法(尽管它实际上非常相似) ,因为它看起来比事件实现(附加/分离等)要简单一些,但仍然与 MVVM 模式很好地保持一致。

在 MVVM WPF 中,我通常把我的视图设计成一个用户控件。这只是你想如何展示它的问题。如果你想让它在一个窗口中,那么你可以做一个 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)我们从一些视图模型打开窗口:

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.) Our Window is allready opened, now we want to close It :

 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 原则”。