WPF: VM-first,以符合mvvm的方式关闭窗口



在我的应用程序中,我打开一个窗口输入表单。在我的App.xaml中,我定义了以下内容:

<DataTemplate DataType="{x:Type ViewModels:EditTicketViewModel}">
<Frame>
<Frame.Content>
<Views:EditTicketView></Views:EditTicketView>
</Frame.Content>
</Frame>
</DataTemplate>

我的应用程序也有一个打开窗口的窗口服务:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DevPortal.Interfaces
{
public interface IWindowService
{
public void ShowWindow(object viewModel, bool showDialog);
}
}

实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using DevPortal.Interfaces;
using Syncfusion.Windows.Shared;
using Syncfusion.SfSkinManager;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace DevPortal.Services
{
public class WindowService : IWindowService
{
public void ShowWindow(object viewModel, bool showDialog)
{
var window = new ChromelessWindow();
window.ResizeMode = ResizeMode.NoResize;
SfSkinManager.SetTheme(window, new Theme("FluentDark"));
window.Content = viewModel;
window.SizeToContent = SizeToContent.WidthAndHeight;
window.Title = viewModel.GetType().GetProperty("Title").GetValue(viewModel).ToString();
window.ShowIcon = false;
if (showDialog)
{
window.ShowDialog();
} else
{
window.Show();
}
}
}
}

如何打开窗口(从MainView中的视图模型)

[RelayCommand]
private void CreateTicket()
{
App.Current.ServiceProvider.GetService<IWindowService>().ShowWindow(new EditTicketViewModel(), true);
}

从ViewModel关闭这个窗口的最好方法是什么?以前,它被用来直接创建视图,在视图的构造函数中,我将订阅视图模型中的关闭事件,但我想这并不是真正的mvc方式。我需要实现某种服务吗?谢谢!

编辑:我忘了说视图是一个页面。所以我正在创建一个以视图模型为内容的窗口,视图模型的数据模板是一个包含页面的框架。

你可以从你的窗口服务返回一个IWindow:

public class WindowService : IWindowService
{
public IWindow ShowWindow(object viewModel, bool showDialog)
{
var window = new ChromelessWindow();
...
return window;
}
}

…然后在视图模型中简单地调用Close()

接口就像这样简单:

public interface IWindow
{
void Close();
}

你的ChromelessWindow实现接口:

public partial class ChromelessWindow : Window, IWindow { ... }

…视图模型只依赖于一个接口。它仍然不知道任何关于视图或实际窗口的事情。IWindow只是一个名字。我可以叫任何名字。

从ViewModel中关闭窗口的最干净的方法是使用附加属性。

public static class perWindowHelper
{
public static readonly DependencyProperty CloseWindowProperty = DependencyProperty.RegisterAttached(
"CloseWindow",
typeof(bool?),
typeof(perWindowHelper),
new PropertyMetadata(null, OnCloseWindowChanged));
private static void OnCloseWindowChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
if (!(target is Window view))
{
return;
}
if (view.IsModal())
{
view.DialogResult = args.NewValue as bool?;
}
else
{
view.Close();
}
}
public static void SetCloseWindow(Window target, bool? value)
{
target.SetValue(CloseWindowProperty, value);
}
public static bool IsModal(this Window window)
{
var fieldInfo = typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic);
return fieldInfo != null && (bool)fieldInfo.GetValue(window);
}
}

在ViewModel中创建ViewClosed属性

private bool? _viewClosed;
public bool? ViewClosed
{
get => _viewClosed;
set => Set(nameof(ViewClosed), ref _viewClosed, value);
}

,然后在视图中,使用附加属性

绑定到它
<Window
...
vhelp:perWindowHelper.CloseWindow="{Binding ViewClosed}" >

在我的博客中详细介绍我对MVVM导航的看法。

最新更新