【WPF】桌面程序开发之窗口的用户控件详解

使用Visual Studio开发工具,我们可以编写在Windows系统上运行的桌面应用程序。其中,WPF(Windows Presentation Foundation)项目是一种常见的选择。然而,对于初学者来说,WPF项目中xaml页面的布局设计可能是一个难点。下面,将简要介绍WPF项目页面中使用的用户控件知识。

文章目录

如果还不知道怎么创建WPF项目, 可以看以下文章,回顾一下再来

Windows系统桌面应用程序编程开发新手入门-打造自己的小工具

可以跳过...
桌面程序开发之xaml页面绑定数据模型详解

页面布局

带后缀名xaml的是页面的布局文件,打开第一个窗体布局文件,内容如下

xml 复制代码
<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>

注意内容中添加一个文本和一个按钮控件

当前设计器显示,如下图

数据绑定

在窗体的代码中修改,绑定数据,

初始化一个自定义对象来绑定的数据,代码如下

csharp 复制代码
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

需要自己单独写出来,代码如下

csharp 复制代码
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,布局内容如下

xml 复制代码
<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>

在用户控件中添加一个文本控件

xml 复制代码
<TextBlock Text="{Binding key1, FallbackValue='zs1028', TargetNullValue='未初始化赋值'}" FontSize="14" Foreground="Red"/>

看文本控件绑定了一个属性key1,默认都是它所在的窗体上绑定的数据模型上的

引用

打开主窗口页面布局文件MainWindow.xaml

在按钮控件后面添加,内容如下

xml 复制代码
<local:UserControl1 />

在主页面布局中使用这个用户控件,

如果显示下划波浪线,提示它不存在,如下图

这需要重新编译下项目,

选中项目名,鼠标右键选择重新生成,如下图

它会自动处理好未添加引用问题,

当前设计器显示,如下图

点击运行,查看效果,

然后点击按钮,这两个文本标签就会一起更新,如下图

这是因为用户控件的属性绑定默认是向上寻找数据的,

找到后会自动绑定到带属性key1DataContext数据上下文对象

控件属性

用户控件是支持嵌套使用的组件。

也就是说,一个用户控件可以包含多个其他用户控件作为其组成部分。

自定义属性

为了防止在嵌套多个用户控件时发生数据绑定的混淆,我们为每个用户控件定义了独特的属性。这样,在实际使用中,就可以通过传递这些属性的值来进行参数传递,从而确保数据的清晰与准确。

可以通过窗体的绑定数据进行参数传递,或者利用父级用户控件中的数据来为其子控件传递参数。

在窗体布局中,给用户控件添加一个自定义的属性,如下图

这个自定义属性提示未找到属性,

需要自己定义一个属性,在用户控件中添加一个属性代码,代码如下

csharp 复制代码
public string MyText { get; set; }

在用户控件布局中的添加一个新的文本控件,

就在之前的文本控件后面添加,内容如下

xml 复制代码
<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代码修改,添加后,代码如下

csharp 复制代码
public string MyText
{
    get
    {
        return GetValue(MyTextProperty) as string;
    }

    set
    {
        SetValue(MyTextProperty, value);
    }
}

其中MyTextProperty属性是一个自定义的静态字段,类型为DependencyProperty,支持绑定数据,

添加这个字段,代码如下

csharp 复制代码
public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText", typeof(String), typeof(UserControl1));

其中传入的参数MyText就是注册的控件属性名称

运行看看效果,如下图

数据绑定

如果要更新那个文本控件内容,就这样做,

在窗体布局中修改一下用户控件的属性为绑定数据,内容如下

csharp 复制代码
<local:UserControl1 MyText="{Binding key1}" />

再运行看看效果,如下图

正如预期,文本控件的内容已经同步更新了。

如果绑定失败,可点击程序窗口上悬浮的调试工具条的绑定图标按钮,如下图

看看为什么会绑定失败

数据监听

如果在用户控件中需要监听属性绑定的数据是否改变,

需要在属性的注册方法中添加一个监听方法,

修改用户控件的代码,代码如下

csharp 复制代码
public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText", typeof(String), typeof(UserControl1), new PropertyMetadata(OnMyTextPropertyChanged));

其中OnMyTextPropertyChanged是监听属性的改变事件,

在创建的对象PropertyMetadata有个参数可以传属性的默认值

在方法OnMyTextPropertyChanged里面,实现更新的处理

csharp 复制代码
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类别

写到这里为止,先溜了...

相关推荐
小码编匠3 小时前
一款 C# 编写的神经网络计算图框架
后端·神经网络·c#
Envyᥫᩣ6 小时前
C#语言:从入门到精通
开发语言·c#
IT技术分享社区12 小时前
C#实战:使用腾讯云识别服务轻松提取火车票信息
开发语言·c#·云计算·腾讯云·共识算法
月落.13 小时前
WPF的<ContentControl>控件
wpf
就是有点傻13 小时前
WPF中的依赖属性
开发语言·wpf
wangnaisheng13 小时前
【WPF】把一个Window放在左上角/右上角顶格显示
wpf
WineMonk13 小时前
.NET WPF CommunityToolkit.Mvvm框架
.net·wpf·mvvm
月落.13 小时前
WPF中的INotifyPropertyChanged接口
wpf
界面开发小八哥13 小时前
界面控件DevExpress WPF中文教程:Data Grid——卡片视图设置
.net·wpf·界面控件·devexpress·ui开发