文章目录
一、用户控价
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
类的公共属性。通过依赖属性机制,这个属性:
- 可在XAML中直接使用:
<local:MyUserControl Text="直接设置值" />
- 支持数据绑定:
<local:MyUserControl Text="{Binding ViewModelProperty}" />
- 可通过代码访问:
myUserControl.Text = "通过代码设置";
4. 依赖属性 vs 普通属性
特性 | 普通属性 | 依赖属性 |
---|---|---|
存储方式 | 实例字段(如 private string _text ) |
由WPF属性系统统一管理 |
默认值 | 在构造函数中设置 | 通过元数据设置(全局唯一) |
数据绑定 | 需要手动实现 INotifyPropertyChanged |
原生支持,自动通知 |
样式/动画支持 | 不支持 | 支持(可被样式覆盖、可动画化) |
继承性 | 无 | 部分属性支持值继承(如 FontSize ) |
※※※
5. 完整工作流程
注册阶段:
- 通过
DependencyProperty.Register
创建属性定义。 - 静态字段
TextProperty
保存属性标识符。
- 通过
CLR包装器(可选但推荐):
public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }
使用阶段:
- XAML中:
<MyUserControl Text="值" />
- 代码中:
myControl.Text = "值";
- 数据绑定时:WPF通过
TextProperty
标识符解析属性。
- XAML中:
总结
- “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;
}
}
}