WPF:首先是VM,以符合MVVM的方式关闭Window

js5cn81o  于 2022-11-26  发布在  其他
关注(0)|答案(2)|浏览(179)

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

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

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

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

        }
    }
}

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

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

从ViewModel中关闭这个窗口的最佳方式是什么?以前我被用来直接创建视图,并且在视图的构造函数中我会订阅视图模型中的一个close事件,但我想这不是MVVM真正的方式。我需要实现某种服务吗?谢谢!
编辑:我忘了说视图是一个页面,所以我创建了一个以视图模型为内容的窗口,视图模型的数据模板是一个包含页面的框架。

bwitn5fc

bwitn5fc1#

例如,您可以从窗口服务返回一个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只是一个名字,我可以被称为任何东西。

ryevplcw

ryevplcw2#

从 windows 的ViewModel关闭 windows 的最简洁方式是使用附加属性。

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

关于我在blog post上的MVVM导航的模式详细信息。

相关问题