WPF入门到跪下 第九章 MVVM-跨模块交互

发布时间:2024年01月14日

MVVM模式下的跨模块交互

在实际开发过程中,经常会遇到多个窗口对象,随之而来的就是对应的多个ViewModel对象,这些对象在一定条件下会发生相互访问的情况,例如VM与不同窗口交互、VM与不同VM交互,这些不同模块对象之间的交互,就是跨模块交互。

MVVM模式下跨模块交互解决方案
面对跨模块交互,常规的解决方案是创建一个“第三方”来作为交互的中转站。

创建一个窗体管理类型,作为第三方

public class WindowManager
{
	private static Dictionary<string, WinEntity> _windows = new Dictionary<string, WinEntity>();

	/// <summary>
	/// 窗体类型注册
	/// </summary>
	/// <param name="type"></param>
	/// <param name="owner"></param>
	public static void Register(Type type, Window owner)
	{
	    _windows.Add(type.Name, new WinEntity { 
	        Type = type,
	        Owner = owner
	    });
	}
	//展示对应的窗口
	public static bool ShowDialog(string winKey, object dataContext)
	{
	    if (_windows.ContainsKey(winKey))
	    {
	        Type type = _windows[winKey].Type;
	        var win = (Window)Activator.CreateInstance(type);
	        //指定所展示的窗口对象的拥有者,设置后子窗口跟主窗口会关联展示
	        win.Owner = _windows[winKey].Owner;
	        //传递上下文参数
	        win.DataContext = dataContext;
	        return win.ShowDialog()==true?true:false;
	    }
	    return false;
	}
}

class WinEntity
{
    public Type Type { get; set; }
    public Window Owner { get; set; }
}

主窗口做窗口类型注册

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        //进行窗体对象类型的注册,后面通过反射获得对应的窗体对象,这里的SecondWindow只是一个简单的显示Hello的窗口
        WindowManager.Register(typeof(SecondWindow), this);
    }
}

命令类型创建

public class CommandBase : ICommand
{
    public event EventHandler CanExecuteChanged;
    public void DoCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    public Func<object, bool> DoCanExecute { get; set; }
    public bool CanExecute(object parameter)
    {
        return DoCanExecute(parameter);
    }

    public Action<object> DoExecute { get; set; }
    public void Execute(object parameter)
    {
        DoExecute(parameter);
    }
}

ViewModel层

public class MainViewModel
{
    public MainModel MainModel { get; set; }
    public CommandBase CommandBase { get; set; }
    
    public MainViewModel()
    {
        CommandBase = new CommandBase
        {
            DoExecute = DoExecute,
            DoCanExecute = DoCanExecute
        };

        MainModel = new MainModel();
    }

    private void DoExecute(object obj)
    {
        //创建并设置VM对象,传递给所访问的窗体对象
        MainViewModel mainViewModel = new MainViewModel();
        mainViewModel.MainModel.Value = 123;
        //跨模块调用窗体对象
        if (WindowManager.ShowDialog("SecondWindow", mainViewModel))
        {
            //根据窗口的操作结果来进行不同的业务逻辑
        }
        else
        {

        }
    }

    private bool DoCanExecute(object obj)
    {
        Debug.WriteLine("DoCanExecute......");
        return true;
    }
}

Model层

public class MainModel
{
    public int Value { get; set; }
}

以上的做法,将对应的窗口类型剥离出来,由WindowManager统一管理,实现各个模块之间的相互隔离。这个方式不仅仅用于ViewModel层访问窗口对象,还能针对不同的跨模块访问情况做出不同的调整。例如跨模块访问方法的ActionManager可以如下编写:

public class MethodManager<T>
{
    private Dictionary<string, Func<T>> _methods = new Dictionary<string, Func<T>>();

    public void Register(string name, Func<T> func)
    {
        _methods.Add(name, func);
    }

    public T Invoke(string name)
    {
        return _methods[name].Invoke();
    }
}
文章来源:https://blog.csdn.net/jjailsa/article/details/135582579
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。