文章目錄
- 前言
- 專欄和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();//重定向ViewModelViewModel = (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倉庫