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

news2024/11/18 16:40:10

使用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 />

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

如果显示下划波浪线,提示它不存在,如下图
在这里插入图片描述
这需要重新编译下项目,

选中项目名,鼠标右键选择重新生成,如下图
在这里插入图片描述
它会自动处理好未添加引用问题,

当前设计器显示,如下图
在这里插入图片描述

点击运行,查看效果,

然后点击按钮,这两个文本标签就会一起更新,如下图
在这里插入图片描述

这是因为用户控件的属性绑定默认是向上寻找数据的,
找到后会自动绑定到带属性key1DataContext数据上下文对象

控件属性

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

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

自定义属性

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

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

在窗体布局中,给用户控件添加一个自定义的属性,如下图
在这里插入图片描述
这个自定义属性提示未找到属性,

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

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类别

写到这里为止,先溜了…
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2177798.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Naive UI 选择器 Select 的:render-label 怎么使用(Vue3 + TS)

项目场景&#xff1a; 在Naive UI 的 选择器 Select组件中 &#xff0c;如何实现下面的效果 &#xff0c;在下拉列表中&#xff0c;左边展示色块&#xff0c;右边展示文字。 Naive UI 的官网中提到过这个实现方法&#xff0c;有一个render-label的api&#xff0c;即&#xff…

Golang | Leetcode Golang题解之第442题数组中重复的数据

题目&#xff1a; 题解&#xff1a; func findDuplicates(nums []int) (ans []int) {for _, x : range nums {if x < 0 {x -x}if nums[x-1] > 0 {nums[x-1] - nums[x-1]} else {ans append(ans, x)}}return }

有通话质量更好的蓝牙耳机推荐吗?高品质的平价开放式耳机推荐

个人认为开放式耳机在通话方面还是表现不错的&#xff0c;主要有以下几个原因&#xff1a; 首先&#xff0c;在麦克风设计与配置方面&#xff1a; 拥有高品质麦克风硬件。优质的开放式耳机往往会配备高性能的麦克风&#xff0c;这些麦克风灵敏度较高&#xff0c;能够精准地捕捉…

1.2.1 HuggingFists安装说明-Linux安装

Linux版安装说明 下载地址 【GitHub】https://github.com/Datayoo/HuggingFists 【百度网盘】https://pan.baidu.com/s/12-qzxARjzRjYFvF8ddUJQQ?pwd2024 安装说明 环境要求 操作系统&#xff1a;CentOS7 硬件环境&#xff1a;至少4核8G&#xff0c;系统使用Containerd…

如何理解矩阵的复数特征值和特征向量?

实数特征值的直观含义非常好理解&#xff0c;它就是在对应的特征向量方向上的纯拉伸/压缩。 而复数特征值&#xff0c;我们可以把它放在复数域中理解。但是这里给出一个不那么简洁、但是更加直观的理解方式&#xff1a;把它放在实空间中。那么复数特征值表现的就是旋转等比放大…

Linux进程间的通信(三)IPC-信号通信和system-V消息队列

目录 信号通信 信号动作的改写 测试 信号的发送 消息队列 消息队列创建要用到的函数 send.c&#xff1a; recv.c 控制消息队列 信号通信 信号通信是一种在 Unix 和类 Unix 系统&#xff08;如 Linux&#xff09;中用于进程间异步通知的机制。信号是一种软件中断&#x…

数据库软题3-专门的集合运算

一、投影&#xff08;筛选列&#xff09; 题1 题2 二、选择(筛选行) 三、连接 3.自然连接 题1-自然连接的属性列数&#xff08;几元关系&#xff09;和元组数 解析&#xff1a; 题2-自然连接的属性列数&#xff08;几元关系&#xff09;和元组数 自然连接后的属性个数 A列…

SpringBoot3+Druid YAML配置

背景 Druid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生&#xff0c;内置强大的监控功能&#xff0c;监控特性不影响性能。功能强大&#xff0c;能防SQL注入&#xff0c;内置Loging能诊断Hack应用行为。现在已经SpringBoot3&#xff0c;Druid的配置也需要随…

java基础(4)类和对象

目录 1.前言 2.正文 2.1类的定义与使用 2.1.1类的定义 2.1.2类的实例化 2.1.3this引用 2.1.3.1 访问当前对象的成员变量 2.1.3.2调用当前对象的成员方法 2.1.3.3构造函数中的 this 2.1.3.4归纳this 2.2封装 2.2.1封装的定义 2.2.2访问修饰符 2.3static 2.3.1sta…

靠谱的建站公司怎么找?2024高端定制开发建站公司推荐

和所有行业一样&#xff0c;网站建设行业内部现在处于一个鱼龙混杂的状态&#xff0c;大多数的网建企业所做的是与模板网站有关的业务&#xff0c;少部分企业专精于定制高端网站。在低端市场逐渐饱和后&#xff0c;无论什么企业都会有开始进行产品升级的需求&#xff0c;而高端…

刚面试完的前端面试题

今天晚上参加了一场长达40多分钟的技术面。我觉得面试官非常专业&#xff0c;问的问题也都是很棒的&#xff01;自己很多知识都需要学习。所以我决定回想并记录下来。回答不对的地方欢迎大家指正&#xff01; 我自己在小本本上回忆出来的大概就是26道题。后期我会持续更新我学习…

(undone) 阅读 MapReduce 论文笔记

参考&#xff1a;https://pdos.csail.mit.edu/6.824/papers/mapreduce.pdf 摘要&#xff1a;简单介绍了 MapReduce 是在大型分布式系统上工作的 Introduction 的内容总结&#xff1a; 1.介绍背景&#xff1a;为什么我们需要分布式系统&#xff1f;MapReduce 的意义是哪些 2.简…

2024icpc(Ⅱ)网络赛补题E

E. Escape 思路&#xff1a; 可以看成 Sneaker 和杀戮机器人都不能在原地停留&#xff0c;然后杀戮机器人有个活动范围限制。如果 Sneaker 和杀戮机器人可以在原地停留&#xff0c;那么 Sneaker 到达一个点肯定会尽可能早&#xff0c;而且时间必须比杀戮机器人到达这个点短。那…

从传统 RAG 到图 RAG,赋予大型语言模型更强大的知识力量

大型语言模型 (LLMs) 在固定数据集上进行训练&#xff0c;其知识在最后一次训练更新时就已固定。 ChatGPT 的常规用户可能已经注意到其众所周知的局限性&#xff1a;“训练数据截止到 2021 年 9 月”。 这种局限性会导致模型产生不准确或过时的响应&#xff0c;因为它们会“幻…

【计算机网络】初识Socket编程,揭秘Socket编程艺术--UDP篇

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 Socket编程准备知识理解源IP地址和目的IP地址 认识端口号 网络字节序 socket编程socket编程接口socket系统调用bzero函数struct soc…

生信机器学习入门4 - 构建决策树(Decision Tree)和随机森林(Random Forest)分类器

机器学习文章回顾 生信机器学习入门1 - 数据预处理与线性回归&#xff08;Linear regression&#xff09;预测 生信机器学习入门2 - 机器学习基本概念 生信机器学习入门3 - Scikit-Learn训练机器学习分类感知器 生信机器学习入门4 - scikit-learn训练逻辑回归&#xff08;L…

【Android 14源码分析】Activity启动流程-2

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…

高并发内存池(六):补充内容

目录 有关大于256KB内存的申请和释放处理方法 处理大于256KB的内存申请 补充内容1 补充内容2 补充内容3 处理大于256KB的内存释放 新增内容1 新增内容2 测试函数 使用定长内存池替代new 释放对象时不传对象大小 补充内容1 补充内容2 补充内容3 补充内容4 测试…

Python(五)-函数

目录 函数的定义与调用 特点 语法格式 函数的参数 函数的返回值 函数嵌套调用 变量的作用域 局部变量 全局变量 函数的多种参数 位置参数 关键字参数 默认参数 可变参数 函数的定义与调用 python函数需要使用def关键字来定义,需要先定义,后调用 特点: 先定义…

课堂讨论:评价计算机性能的指标

**课堂讨论&#xff1a;评价计算机性能的指标** --- ### 课堂开始 **王老师**&#xff1a;同学们&#xff0c;今天我们来讨论如何评价计算机性能的指标。小明&#xff0c;你知道有哪些指标吗&#xff1f; **小明**&#xff1a;嗯...有吞吐率和响应时间吧&#xff1f;&#…