Article directory
Preface
This time we will explain the component development process of WPF. Component development is a method that can greatly reduce the difficulty of our page development and reduce code coupling. This allows us to disassemble any WPF interface. Because I have written Vue, I will develop WPF into components according to the logic of Vue.
Column and Gitee repository
Dependency properties
In order to improve performance, WPF limits the use of Binding. Properties need to be registered in advance as dependent properties or additional properties in order to use Binding syntax. The reason is that each bindable attribute needs to open up storage space in memory. WPF cannot bind by default and needs to be actively declared.
This is why the memory overhead of Elelctron, Fullter, etc. is so large, because they also set up memory space that may be useless.
Bilibili Microsoft series of technical tutorials Detailed explanation of WPF dependency properties
Practical combat: zoom out, full screen, close button
Here I will explain the difference between Window and UserControl. Window is the entire window, and UserControl is the control. Window is responsible for some methods of the window, such as dragging, zooming in and out. Since we are developing components, we need to pass this of the main window to the sub-components.
Dependency attribute operation encapsulation
Let’s take a look at my summary blog first.
The main window passes this itself to the TitleView title control
Because we develop View and ViewModel, all Views only have the function of passing parameters and exposing dependency properties. The actual business is done by ViewModel.
So the direction we pass is
main code
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;
}
}
Dependency property method encapsulation
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
It’s just a binding button event, I won’t let it go
For detailed code, please see my Gitee warehouse address