使用Visual Studio开发工具,我们可以编写在Windows系统上运行的桌面应用程序。其中,WPF(Windows Presentation Foundation)项目是一种常见的选择。然而,对于初学者来说,WPF项目中xaml页面的布局设计可能是一个难点。下面,将简要介绍WPF项目页面中使用的用户控件知识。
文章目录
- 页面布局
- 数据绑定
- 数据模型
- 用户控件
- 创建
- 引用
- 控件属性
- 自定义属性
- 注册属性
- 数据绑定
- 数据监听
如果还不知道怎么创建WPF项目, 可以看以下文章,回顾一下再来
Windows系统桌面应用程序编程开发新手入门-打造自己的小工具
可以跳过…
桌面程序开发之xaml页面绑定数据模型详解
页面布局
带后缀名xaml的是页面的布局文件,打开第一个窗体布局文件,内容如下
<Window x:Class="WpfApp2.MainWindow"
...
xmlns:local="clr-namespace:WpfApp2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<!-- 这里设置统一控件的样式 -->
</Window.Resources>
<Grid>
<TextBlock Text="{Binding key1, FallbackValue='zs1028', TargetNullValue='未初始化赋值'}" FontSize="14" Foreground="Blue"/>
<Button Click="Button_Click">点击按钮</Button>
<!-- 这里开始添加用户控件布局 -->
</Grid>
</Window>
注意内容中添加一个文本和一个按钮控件
当前设计器显示,如下图
数据绑定
在窗体的代码中修改,绑定数据,
初始化一个自定义对象来绑定的数据,代码如下
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// 用一个自定义对象来持有数据DataContext
this.DataContext = new DataModel();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
DataModel data = (DataModel)this.DataContext;
data.key1 = "hello zs1028";
}
}
数据模型
上面用到了一个数据模型类DataModel
,
需要自己单独写出来,代码如下
class DataModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string key1
{
get { return _key1; }
set
{
_key1 = value;
OnPropertyChanged(nameof(key1));
}
}
private string _key1 { get; set; }
public Data()
{
}
}
用户控件
在页面布局中,那些可以拼接和细分的区块,均可被视为用户控件。
用户控件具有高度的灵活性和可复用性,既可以自行创建,也可以利用已有的控件进行复用。这样的特性使得用户控件在管理和维护上变得非常便捷,同时也大大提升了使用的便利性。
前面所讲述的是对基础知识的理解和掌握,
接下来,我将详细阐述一下,如何创建用户控件,
创建
在项目目录下,新建一个文件夹Controls
来存放一些用户控件,
然后在选中的文件夹名称下点鼠标右键,如下图
假设新建的用户控件名称为UsesrControl1
,如下图
添加后,打开这个文件UserControl1.xaml
,布局内容如下
<UserControl x:Class="WpfApp2.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
...
xmlns:local="clr-namespace:WpfApp2"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<!-- 这里开始添加控件布局 -->
</Grid>
</UserControl>
在用户控件中添加一个文本控件
<TextBlock Text="{Binding key1, FallbackValue='zs1028', TargetNullValue='未初始化赋值'}" FontSize="14" Foreground="Red"/>
看文本控件绑定了一个属性
key1
,默认都是它所在的窗体上绑定的数据模型上的
引用
打开主窗口页面布局文件MainWindow.xaml
,
在按钮控件后面添加,内容如下
<local:UserControl1 />
在主页面布局中使用这个用户控件,
如果显示下划波浪线,提示它不存在,如下图
这需要重新编译下项目,
选中项目名,鼠标右键选择重新生成
,如下图
它会自动处理好未添加引用问题,
当前设计器显示,如下图
点击运行,查看效果,
然后点击按钮,这两个文本标签就会一起更新,如下图
这是因为用户控件的属性绑定默认是向上寻找数据的,
找到后会自动绑定到带属性key1
的DataContext
数据上下文对象
控件属性
用户控件是支持嵌套使用的组件。
也就是说,一个用户控件可以包含多个其他用户控件作为其组成部分。
自定义属性
为了防止在嵌套多个用户控件时发生数据绑定的混淆,我们为每个用户控件定义了独特的属性。这样,在实际使用中,就可以通过传递这些属性的值来进行参数传递,从而确保数据的清晰与准确。
可以通过窗体的绑定数据进行参数传递,或者利用父级用户控件中的数据来为其子控件传递参数。
在窗体布局中,给用户控件添加一个自定义的属性,如下图
这个自定义属性提示未找到属性,
需要自己定义一个属性,在用户控件中添加一个属性代码,代码如下
public string MyText { get; set; }
在用户控件布局中的添加一个新的文本控件,
就在之前的文本控件后面添加,内容如下
<TextBlock Margin="10,20" Text="{Binding MyText, FallbackValue='zs1028', TargetNullValue='未初始化赋值', RelativeSource={RelativeSource AncestorType=local:UserControl1}}" FontSize="14" Foreground="Orange"/>
其中
RelativeSource
,可将控件绑定到自身或其父控件上
如对象RelativeSource
使用属性AncestorType
为用户控件类型,它就会绑定到自身,
否则,它会自动绑定到父控件的DataContext
数据上下文对象。
运行的话,如果引发异常,如下图
提示这个属性未注册,需要设置可以用来支持绑定
Binding
的属性类型
注册属性
将属性MyText
代码修改,添加后,代码如下
public string MyText
{
get
{
return GetValue(MyTextProperty) as string;
}
set
{
SetValue(MyTextProperty, value);
}
}
其中MyTextProperty
属性是一个自定义的静态字段,类型为DependencyProperty
,支持绑定数据,
添加这个字段,代码如下
public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText", typeof(String), typeof(UserControl1));
其中传入的参数
MyText
就是注册的控件属性名称
运行看看效果,如下图
数据绑定
如果要更新那个文本控件内容,就这样做,
在窗体布局中修改一下用户控件的属性为绑定数据,内容如下
<local:UserControl1 MyText="{Binding key1}" />
再运行看看效果,如下图
正如预期,文本控件的内容已经同步更新了。
如果绑定失败,可点击程序窗口上悬浮的调试工具条的绑定图标按钮,如下图
看看为什么会绑定失败
数据监听
如果在用户控件中需要监听属性绑定的数据是否改变,
需要在属性的注册方法中添加一个监听方法,
修改用户控件的代码,代码如下
public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText", typeof(String), typeof(UserControl1), new PropertyMetadata(OnMyTextPropertyChanged));
其中
OnMyTextPropertyChanged
是监听属性的改变事件,
在创建的对象PropertyMetadata
有个参数可以传属性的默认值
在方法OnMyTextPropertyChanged
里面,实现更新的处理
private static void OnMyTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uc = d as UserControl1;
var newValue = e.NewValue as string;
var oldValue = e.OldValue as string;
//...
}
其中NewValue
是改变后的值,OldValue
是改变前的值,都是对象,取值前需要做对应的类型转换,
处理完时可调用用户控件对象UserControl1
来更新,
更多了解请参考微软官方文档的RelativeSource类别
写到这里为止,先溜了…