WPF学习(四)

发布于:2025-07-05 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、用户控价

1.1 依赖属性的注册

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. 参数详解

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中直接使用
    <local:MyUserControl Text="直接设置值" />
    
  2. 支持数据绑定
    <local:MyUserControl Text="{Binding ViewModelProperty}" />
    
  3. 可通过代码访问
    myUserControl.Text = "通过代码设置";
    

4. 依赖属性 vs 普通属性

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

※※※
5. 完整工作流程

  1. 注册阶段

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

    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

<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

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

<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

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;
        }
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到