文章目录
- 前言
- 专栏和Gitee仓库
- 依赖属性
- 实战:缩小,全屏,关闭按钮
- 依赖属性操作封装
- 主窗口传递this本身给TitleView标题控件
- 主要代码
- MainWindow.xmal
- MainWindow.cs
- 依赖属性方法封装
- TitleView.cs
- TitleViewModel
- TitleViewModel
- 实现效果
前言
这次我们来讲解一下WPF 的组件化开发流程,组件化开发是是可以极大降低我们页面开发难度,降低代码耦合的方法。这让我们可以将任意WPF界面进行拆解。因为我写过Vue,所以我会按照Vue的逻辑将WPF进行组件化开发。
专栏和Gitee仓库
WPF仿网易云 Gitee仓库
WPF仿网易云 CSDN博客专栏
依赖属性
WPF为了提高性能,限制了Binding的使用。需要将属性提前注册为依赖属性或者附加属性,才能解决使用Binding语法。原因是每个能binding的属性需要在内存中开辟存储空间。WPF默认不能Binding,需要主动声明才可以。
这个就是为什么Elelctron,Fullter等内存开销那么大,是因为他们的将可能没用的的内存空间也设置了。
博客园 痕迹g WPF依赖属性详解
B站 十月的寒流 WPF 中依赖属性及附加属性的概念及用法
B站 微软系列技术教程 WPF依赖属性详解
实战:缩小,全屏,关闭按钮
这里我讲解一下Window和UserControl两者的区别。Window就是整个窗口,UserControl就是控件。Window负责窗口的一些方法,比如拖拽,缩小放大。而我们是组件化开发,我们就需要将主窗口的this传给子组件
依赖属性操作封装
这里先去看我这个总结的博客。
WPF 用户控件依赖属性赋值
主窗口传递this本身给TitleView标题控件
因为我们是View和ViewModel开发,所有的View只有传递参数和暴露依赖属性的作用,实际的业务是ViewModel去做的。
所以我们传递的方向是
主要代码
MainWindow.xmal
<Window x:Class="BlankApp1.Views.MainWindow"
......>
<!--需要主动设置名称,不然会Binding错误-->
<Window.DataContext>
<ViewModels:MainWindowViewModel x:Name="MainWindowViewModel" />
</Window.DataContext>
<DockPanel LastChildFill="True">
<!--其它代码-->
<Grid DockPanel.Dock="Top"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
Height="auto">
<!--手动指定DataContext-->
<Views:TitleView MainWindow="{Binding MainWindow, ElementName=MainWindowViewModel}" />
</Grid>
</DockPanel>
</Window>
MainWindow.cs
public partial class MainWindow : Window
{
public MainWindowViewModel ViewModel { get; set; }
public MainWindow()
{
InitializeComponent();
//重定向ViewModel
ViewModel = (MainWindowViewModel)DataContext;
ViewModel.MainWindow = this;
}
}
依赖属性方法封装
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace BlankApp1.Utils
{
public class MyWpfExtension<View> where View : class
{
/// <summary>
/// 简化依赖注入代码
/// </summary>
/// <typeparam name="View"></typeparam>
/// <typeparam name="Value"></typeparam>
/// <param name="name"></param>
/// <param name="action"></param>
/// <returns></returns>
public DependencyProperty DependencyPropertySet<Value>(string name, Action<View, Value> action)
{
var res = DependencyProperty.Register(name, typeof(Value), typeof(View), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback((item, res) =>
{
var model = item as View;
var value = (Value)res.NewValue;
if (model != null)
{
action(model, value);
}
else
{
throw new Exception("model value is null");
}
})));
return res;
}
}
}
TitleView.cs
namespace BlankApp1.Views
{
/// <summary>
/// TitleView.xaml 的交互逻辑
/// </summary>
public partial class TitleView : UserControl
{
//这个只是为了代码提示,不涉及逻辑
public MainWindow MainWindow { get; set; }
//初始化依赖属性构造器
public static readonly MyWpfExtension<TitleView> MyWpfExtension = new MyWpfExtension<TitleView>();
//这个是简化后的依赖属性
public static readonly DependencyProperty MainWindowProperty =
MyWpfExtension.DependencyPropertySet<MainWindow>("MainWindow", (view, value) =>
{
//通过依赖属性来获取MainWindow的对象
view.TitileViewModel.MainWindow = value;
});
/// <summary>
/// DataContext的数据
/// </summary>
public TitileViewModel TitileViewModel { get; set; }
public TitleView()
{
InitializeComponent();
//拿到DataContext数据重定向
TitileViewModel = (TitileViewModel)DataContext;
}
}
}
TitleViewModel
using BlankApp1.Models;
using BlankApp1.Views;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace BlankApp1.ViewModels
{
public partial class TitileViewModel:ObservableObject
{
public RelayCommand CloseWindow { get; set; }
public RelayCommand MaxOrNormalWindow { get; set; }
public RelayCommand MiniWindow { get; set; }
public MainWindow MainWindow { get; set; }
public TitileViewModel() {
//.......其它代码
CloseWindow = new RelayCommand(() => {
MainWindow.Close();
Debug.WriteLine("关闭窗口");
});
MaxOrNormalWindow = new RelayCommand(() => {
if(MainWindow.WindowState == WindowState.Normal)
{
MainWindow.WindowState = WindowState.Maximized;
MainWindow.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
MainWindow.MaxWidth = SystemParameters.MaximizedPrimaryScreenWidth;
}
else
{
MainWindow.WindowState = WindowState.Normal;
}
Debug.WriteLine("最大化或正常窗口");
});
MiniWindow = new RelayCommand(() => {
MainWindow.WindowState = WindowState.Minimized;
Debug.WriteLine("缩小窗口");
});
}
}
}
TitleViewModel
就是绑定按钮事件,我就不放了
详细代码看我的Gitee仓库地址
WPF仿网易云 Gitee仓库