【WPF】IOC控制反转的应用:弹窗但不互相调用ViewModel

全称:Inversion of Control,控制反转

场景:A页面需要调用B/C页面等,防止直接在VM中新建别的页面实例,使用IOC设计架构;

创建Service,在Service中实现页面的实例创建和定义页面输入输出参数。

在MainView中注册A、B、C页面的Service。

A需要调用B时,调用B的Service。

此架构思路可以在MVVM基础上,减少不同模块的耦合。

可以所有模块的页面都注册服务。让VM之间不存在互相调用

手动实现

IOC类

csharp 复制代码
public static class IoC
{
	private static readonly Dictionary<Type, object> MAP;

	static IoC()
	{
		MAP = new Dictionary<Type, object>();
	}

	public static void Register<T>(T instance)
	{
		MAP[typeof(T)] = instance;
	}

	public static T Provide<T>()
	{
		if (MAP.TryGetValue(typeof(T), out object obj) && obj is T t)
		{
			return t;
		}

		throw new Exception("No registered service of type " + typeof(T));
	}
}

IView接口

csharp 复制代码
public interface IView
{
    /// <summary>
    /// Close the view with the given result
    /// </summary>
    void CloseDialog(bool result);
}

页面B实现IView

复制代码
public partial class ChildValuePopup : Window, IView
{
    public ChildValueEditPopupViewModel ViewModel => (ChildValueEditPopupViewModel)this.DataContext;

    public ChildValuePopup()
    {
        InitializeComponent();
        DataContext = new ChildValueEditPopupViewModel(this);
    }

    public void CloseDialog(bool result)
    {
        this.DialogResult = result;
        this.Close();
    }
}

IViewBService页面B的Service接口

csharp 复制代码
public interface IChildValueEditPopupService
{
//打开B页面方法,及其输入输出参数
    Task<ChildValueEditPopupResult> ChildValueEditPopupOpenAsync(GirdDataModel data);

    ChildValueEditPopupResult ChildValueEditPopupOpen(GirdDataModel data);
}

//输出参数类定义
//IsSuccess是否成功打开B页面
public class ChildValueEditPopupResult : ObservableObject
{
    public bool IsSuccess { get; set; }

    private object _setValue;

    public string code { get; set; }

    public object setValue { get=>_setValue; set=>OnPropertyChanged(ref _setValue,value); }
}

ViewBService页面B的Service实现

csharp 复制代码
internal class ChildValueEditPopupService : IChildValueEditPopupService
{
	public ChildValueEditPopupResult ChildValueEditPopupOpen(GirdDataModel data)
	{
		var popup = new ChildValuePopup();
		popup.ViewModel.Code = data.code;
		popup.ViewModel.ChildValues = Copy.DeepCopy( data.childValues);
		popup.ViewModel.SetValue = data.setValue;

		bool result = popup.ShowDialog() == true;
		if (!result) {
			return new ChildValueEditPopupResult() { IsSuccess = false};
		}

		return new ChildValueEditPopupResult()
		{
			IsSuccess = true,
			code = popup.ViewModel.Code,
			setValue = popup.ViewModel.SetValue,
		}; 
	}

	public async Task<ChildValueEditPopupResult> ChildValueEditPopupOpenAsync(GirdDataModel data) {
		return await Application.Current.Dispatcher.InvokeAsync(() => {
			return ChildValueEditPopupOpen(data);
		});
	}
}

注册服务,全局页面MainView

复制代码
public MainWindow()
{
    InitializeComponent();
    IoC.Register<IChildValueEditPopupService>(new ChildValueEditPopupService());
}

使用服务,页面A打开页面B

复制代码
private void ChildValueEditPopupOpen(GirdDataModel data) {
    IChildValueEditPopupService service = IoC.Provide<IChildValueEditPopupService>();
    ChildValueEditPopupResult res = service.ChildValueEditPopupOpen(data);
    if (res.IsSuccess) {
        data.setValue = res.setValue;
    }
}
相关推荐
NG4771 小时前
【软件设计与体系结构】-策略设计模式
java·设计模式·软件工程
CaffeinePro2 小时前
SOLID五大设计原则:重构优雅代码与架构的底层规范
设计模式·架构
饮茶三千3 小时前
电子保函模板编辑器实战二:HTML→FTL 编译转换的设计与实现
前端·vue.js·设计模式
唐青枫3 小时前
看懂 IL 的关键:C#.NET 栈机执行模型实战拆解
c#·.net
Kel3 小时前
Node.js 本质:从全脉络视角理解运行时原理
javascript·设计模式·node.js
我才是银古4 小时前
从零构建 Windows 桌面 RPA 框架:Go 与 .NET 的跨语言协奏
c#·go·rpa
码哥字节5 小时前
11 万 Star 的 Spec Kit,90% 的工程师只用它解决了 10% 的问题
设计模式·vibe coding·github spec kit
我登哥MVP5 小时前
走进 Gang of Four 设计模式:访问者模式
java·设计模式·访问者模式·原型模式
逝水无殇5 小时前
C# 正则表达式详解
开发语言·后端·正则表达式·c#
朱永博6 小时前
使用Onnruntime实现Padim/Patchcore推理
开发语言·c#