WPF Imitation NetEase Cloud Construction Notes (2): Component Development

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

WPF imitates NetEase Cloud Gitee warehouse

WPF imitates NetEase Cloud CSDN blog column

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.

Blog Park Detailed explanation of WPF dependency properties

Station B October Cold Snap The concept and usage of dependent properties and attached properties in WPF

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.

WPF user control relies on property assignment

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

MainWindow
MainWindowViewModel
TitleView的MainWindow依赖属性
TitleViewModel的MainWindow

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

WPF imitates NetEase Cloud Gitee warehouse

achieve effect

Insert image description here

Guess you like

Origin blog.csdn.net/qq_44695769/article/details/134899341