WPF仿网易云搭建笔记(2):组件化开发

2023-12-13 03:40:24

前言

这次我们来讲解一下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
MainWindowViewModel
TitleView的MainWindow依赖属性
TitleViewModel的MainWindow

主要代码

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仓库

实现效果

在这里插入图片描述

文章来源:https://blog.csdn.net/qq_44695769/article/details/134899341
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。