文章目录
专栏和Gitee仓库
前言
本篇主要以理论为主,讲解WPF中的信息流,以我个人的主观理解为主。
信息流
信息流简单来说就是各个代码之间如何通讯。一般来说,前端页面的元素分为三类。
- 窗体元素:窗体元素是整个窗口。一般来说我们WPF都是单窗口项目。
- 页:页就是最小业务逻辑整体,每个页都能实现一个完整的功能,比如用户设置页,数据列表页。在WPF中就是UserController
- 组件/控件:最小逻辑单元,用于将复杂的逻辑简化。比如统计图控件,加载控件。WPF中是UserController。具有高度复用性。
后端是服务类[Services],用于处理整体的数据逻辑。将WPF的前端交互转化为真实的数据代码。
信息流一般有三种方式:
- 父子通讯:一般用于页和组件,因为页和组件是父子关系。
- 消息定义:一般用于页和页,因为页和页是兄弟关系。
- IOC容器:一般是用于Service类
父子通讯
父子通讯一般遵守两个原则:
- 主动暴露,有限交互:父子通讯必须要将通讯部分主动暴露,使用函数封装。
- 单向数据流:父子通讯通道不同。一般来说是父通过数据驱动子,子通过回调父。
父数据驱动子
这个就是我们上节课说的依赖属性。每次binding的数据更新都会驱动依赖属性交互。这里不展开说明
子回调父
这里我们用Action作为回调的函数,代码功能基于我们上次的代码
流程图
子组件 子组件View依赖属性CallBack 子组件ViewModel调用 父组件 父组件ViewModel声明回调 XAML设置子组件回调
测试用例
父组件ViewModel
csharp
namespace BlankApp1.ViewModels
{
public partial class MainWindowViewModel : ObservableObject
{
.......其它代码
/// <summary>
/// 声明回调函数
/// </summary>
[ObservableProperty]
private Action<string> mainTestShow;
public MainWindowViewModel()
{
//实例化回调函数
MainTestShow = new Action<string>((msg) =>
{
Debug.WriteLine("主函数回调"+msg);
});
}
}
}
子组件ViewModel声明和使用
csharp
namespace BlankApp1.ViewModels
{
public partial class TitileViewModel:ObservableObject
{
//其它代码
public RelayCommand MiniWindow { get; set; }
//父组件回调
public Action<string> TestCallBack { get; set; }
public MainWindow MainWindow { get; set; }
public TitileViewModel() {
//其它代码
MiniWindow = new RelayCommand(() => {
MainWindow.WindowState = WindowState.Minimized;
//父组件回调函数
TestCallBack("缩小窗口");
//本身打印
Debug.WriteLine("缩小窗口");
});
}
}
}
子组件依赖属性
csharp
namespace BlankApp1.Views
{
/// <summary>
/// TitleView.xaml 的交互逻辑
/// </summary>
public partial class TitleView : UserControl
{
//这个只是为了代码提示,不涉及逻辑
public MainWindow MainWindow { get; set; }
public Action<string> TestCallBack { get; set; }
//初始化依赖属性构造器
public static readonly MyWpfExtension<TitleView> MyWpfExtension = new MyWpfExtension<TitleView>();
//将回调函数注入
public static readonly DependencyProperty TestCallBackProperty =
MyWpfExtension.DependencyPropertySet<Action<string>>("TestCallBack", (view, value) =>
{
view.TitileViewModel.TestCallBack = value;
});
/// <summary>
/// DataContext的数据
/// </summary>
public TitileViewModel TitileViewModel { get; set; }
public TitleView()
{
InitializeComponent();
//拿到DataContext数据重定向
TitileViewModel = (TitileViewModel)DataContext;
TitileViewModel.UserName = "小王";
}
}
}
父子回调绑定
结果和预期一致
csharp
MiniWindow = new RelayCommand(() => {
MainWindow.WindowState = WindowState.Minimized;
//父组件回调函数
TestCallBack("缩小窗口");
//本身打印
Debug.WriteLine("缩小窗口");
});
完整代码
完整代码可以看我的Gitee仓库
结论
父子通讯问题解决了之后,我们就可以完美的组件化开发WPF项目了。但是由于父子通讯是父子关系通讯,有些组件是兄弟关系,没有上下级,这个就需要另外的信息通讯方案了。我将会在下一节进行介绍。