WPF学习(四)

文章目录

  • 一、用户控价
    • [1.1 依赖属性的注册](#1.1 依赖属性的注册)
    • [1.2 具体使用](#1.2 具体使用)

一、用户控价

1.1 依赖属性的注册

csharp 复制代码
using System.Windows;
using System.Windows.Controls;

namespace WpfApp
{
    public partial class MyUserControl : UserControl
    {
        // 依赖属性:外部可绑定的文本
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register(
                "Text",
                typeof(string),
                typeof(MyUserControl),
                new FrameworkPropertyMetadata(
                    string.Empty,
                    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                    OnTextPropertyChanged
                )
            );

        public string Text
        {
            get => (string)GetValue(TextProperty);
            set => SetValue(TextProperty, value);
        }

        // 自定义事件:提交按钮点击
        public static readonly RoutedEvent SubmitClickedEvent =
            EventManager.RegisterRoutedEvent(
                "SubmitClicked",
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(MyUserControl)
            );

        public event RoutedEventHandler SubmitClicked
        {
            add => AddHandler(SubmitClickedEvent, value);
            remove => RemoveHandler(SubmitClickedEvent, value);
        }

        public MyUserControl()
        {
            InitializeComponent();
            DataContext = new MyUserControlViewModel(this);
        }

        private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (MyUserControl)d;
            control.RaiseEvent(new RoutedEventArgs(SubmitClickedEvent));
        }
    }
}

这段代码是在WPF中注册依赖属性(Dependency Property) 的标准写法,下面来详细解释它的作用和参数含义:

1. 函数整体作用
DependencyProperty.Register 是WPF中创建依赖属性的核心方法。它做了两件事:

  • 定义属性元数据:包括属性名称、类型、所有者类型、默认值等。
  • 返回属性标识符 :通过静态字段(如 TextProperty)保存,用于后续通过 GetValue/SetValue 访问属性值。

2. 参数详解

csharp 复制代码
public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register(
        "Text",                  // 参数1:属性名称(字符串)
        typeof(string),          // 参数2:属性类型(Type)
        typeof(MyUserControl),   // 参数3:所有者类型(Type)
        new FrameworkPropertyMetadata(  // 参数4:元数据
            string.Empty,    // 默认值
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,  // 绑定模式
            OnTextPropertyChanged  // 值变更回调
        )
    );

参数1:"Text"

  • 含义 :这是依赖属性的名称,必须与CLR包装器属性名一致(即类中的 public string Text { get; set; })。
  • 作用 :WPF内部通过这个名称识别属性,例如在XAML中使用 <MyUserControl Text="Hello" />

参数2:typeof(string)

  • 含义:属性的类型,这里是字符串类型。
  • 作用:确保属性值类型安全,WPF会自动进行类型检查。

参数3:typeof(MyUserControl)

  • 含义:声明该依赖属性的所有者类型,即哪个类拥有这个属性。
  • 作用 :允许同一个依赖属性被多个类共享(通过 AddOwner 方法),但这里 MyUserControl 是原始所有者。

参数4:FrameworkPropertyMetadata

  • 默认值(string.Empty):属性未被显式设置时的默认值。
  • 绑定模式(BindsTwoWayByDefault)
    • 表示此属性的默认绑定模式是双向绑定(Mode=TwoWay)。
    • 例如:<MyUserControl Text="{Binding SomeValue}" /> 会自动成为双向绑定。
  • 回调方法(OnTextPropertyChanged)
    • 当属性值变化时,WPF会自动调用这个静态方法。
    • 常用于实现属性变更通知或依赖操作。

3. 参数"Text"属于谁?

参数 "Text"MyUserControl 类的公共属性。通过依赖属性机制,这个属性:

  1. 可在XAML中直接使用

    xml 复制代码
    <local:MyUserControl Text="直接设置值" />
  2. 支持数据绑定

    xml 复制代码
    <local:MyUserControl Text="{Binding ViewModelProperty}" />
  3. 可通过代码访问

    csharp 复制代码
    myUserControl.Text = "通过代码设置";

4. 依赖属性 vs 普通属性

特性 普通属性 依赖属性
存储方式 实例字段(如 private string _text 由WPF属性系统统一管理
默认值 在构造函数中设置 通过元数据设置(全局唯一)
数据绑定 需要手动实现 INotifyPropertyChanged 原生支持,自动通知
样式/动画支持 不支持 支持(可被样式覆盖、可动画化)
继承性 部分属性支持值继承(如 FontSize

※※※
5. 完整工作流程

  1. 注册阶段

    • 通过 DependencyProperty.Register 创建属性定义。
    • 静态字段 TextProperty 保存属性标识符。
  2. CLR包装器(可选但推荐):

    csharp 复制代码
    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }
  3. 使用阶段

    • XAML中:<MyUserControl Text="值" />
    • 代码中:myControl.Text = "值";
    • 数据绑定时:WPF通过 TextProperty 标识符解析属性。

总结

  • "Text" 参数 :是 MyUserControl 类的公共属性名,用于外部访问。
  • 依赖属性机制:让属性具备动态值解析、数据绑定、样式支持等高级特性,是WPF控件开发的核心技术。

1.2 具体使用

MainWindow.xaml

xml 复制代码
<Window x:Class="WpfApp2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp2"
        
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel>
            <local:UserControl1 Margin="10" Height="200" Width="250" x:Name="userControl"/>
            <Button Content="button1" Click="Button_Click_1"/>
            <Button Content="button2" Click="Button_Click_2"/>
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp2
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }


        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            userControl.Text = "你大爷";
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            userControl.Text = "你 好";
        }
    }
}
	

UserControl1.xaml

xml 复制代码
<UserControl x:Class="WpfApp2.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApp2"
             mc:Ignorable="d" 
             d:DesignHeight="100" d:DesignWidth="200">
    <Grid>
        <TextBox x:Name="txtInput" Margin="10" />
        <Button Content="提交" Click="Button_Click" Margin="10,50,10,10" />
        <TextBlock x:Name="lblOutput" Margin="10,90,10,10" />
    </Grid>
</UserControl>

UserControl1.xaml.cs

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp2
{
    /// <summary>
    /// UserControl1.xaml 的交互逻辑
    /// </summary>
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            lblOutput.Text = "你输入的是:" + txtInput.Text;
        }
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register(
            "Text",                // 属性名
            typeof(string),        // 属性类型
            typeof(UserControl1), // 所有者类型
            new PropertyMetadata(  // 元数据
                string.Empty,      // 默认值
                OnTextPropertyChanged  // 值变更回调
            )
            );

        public string Text
        {
            get => (string)GetValue(TextProperty);
            set => SetValue(TextProperty, value);
        }

        private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (UserControl1)d;
            control.lblOutput.Text = "属性值:" + e.NewValue;
        }
    }
}
相关推荐
Scout-leaf2 天前
WPF新手村教程(三)—— 路由事件
c#·wpf
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode