【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;
    }
}
相关推荐
十五年专注C++开发6 分钟前
面试题:C++11在C++98基础上增加了哪些内容?
开发语言·c++·设计模式·面试·stl·适配器模式
都叫我大帅哥1 小时前
代码界的「跨界婚姻」:桥接模式的鹊桥艺术
java·后端·设计模式
wqq10271 小时前
WPF 使用 DI EF CORE SQLITE
sqlite·wpf
独爱竹子的功夫熊猫2 小时前
从复杂到优雅:用建造者和责任链重塑代码架构
java·后端·设计模式
观无2 小时前
关于Newtonsoft.Json
c#
唐青枫3 小时前
C# 如何比较两个List是否相等?
c#·.net
搬砖工程师Cola8 小时前
<C#>在 C# .NET 6 中,使用IWebHostEnvironment获取Web应用程序的运行信息。
开发语言·c#·.net
找了一圈尾巴12 小时前
设计模式(结构型)-桥接模式
设计模式·桥接模式
匹马夕阳12 小时前
java开发中的设计模式之单例模式
java·单例模式·设计模式
Dazer00714 小时前
C# 运行web项目
c#