依赖属性相当于扩充了 WPF 标签的原有属性列表,并可以使用 WPF 的绑定功能,可谓是十分方便的;用户控件则相当于代码重用的一种方式;以上几点分开来还是比较好理解的,不过要用到MVVM 模式中,还是要探索一番的。

我们先新建一个用户控件(UC_FoodsPanel.xaml),里面放一个 StackPanel:

 
 
 
 
 

XHTML

 
  1. <UserControl x:Class="Note.UC_FoodsPanel"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  4. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6. mc:Ignorable="d"
  7. d:DesignHeight="450" d:DesignWidth="800">
  8. <StackPanel x:Name="SpFoods" MinWidth="620"/>
  9. </UserControl>

然后在其后台添加依赖属性相关代码:

C#

  1. public List<UC_FoodItem> Items
  2. {
  3. get => (List<UC_FoodItem>)GetValue(ItemsProperty);
  4. set => SetValue(ItemsProperty, value);
  5. }
  6.  
  7. // Using a DependencyProperty as the backing store for Items. This enables animation, styling, binding, etc...
  8. public static readonly DependencyProperty ItemsProperty =
  9. DependencyProperty.Register(nameof(Items), typeof(List<UC_FoodItem>), typeof(UC_FoodsPanel),
  10. new PropertyMetadata(null, PropertyChangedCallback, null));
  11.  
  12. private static void PropertyChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
  13. {
  14. if (args.NewValue is List<UC_FoodItem> newValue)
  15. {
  16. try
  17. {
  18. var control = obj as UC_FoodsPanel;
  19. control.SpFoods.Children.Clear();
  20.  
  21. foreach (var item in newValue)
  22. {
  23. control.SpFoods.Children.Add(item);
  24. }
  25. }
  26. catch (Exception ex)
  27. {
  28. Console.WriteLine(ex.ToString());
  29. MessageBox.Show($"载入数据出错:{ex.Message}");
  30. }
  31. }
  32. }

依赖属性相关内容可参考网上的《WPF 系列 —— 控件添加依赖属性 – 朝兮兮 – 博客园》 一文,添加依赖属性的方法为 —— 输入 propdp 再双击 tab 键。

上面代码中,我们添加的依赖属性为 Items,是一个 UC_FoodItem 类的列表。关键在于属性改变时的回调函数 PropertyChangedCallback,其 obj 参数代表属性绑定的控件,即此处的 UC_FoodsPanel,args 参数中有 OldValue 和 NewValue,分别代表属性改变前后的值。此处即取改变后的值 —— 一个列表 —— 赋给用户控件中的 StackPanel。

这样之后,我们在其它页面(Views\\MainWindowView.xaml)使用这个用户控件的时候,就可以使用 Items 属性了:

XHTML

  1. <note:UC_FoodsPanel Items="{Binding Items}"></note:UC_FoodsPanel>

然后在这个页面的 ViewModel 中(ViewModels\\MainWindowViewModel.cs)设置需要绑定的值:

C#
 
  1. private List<UC_FoodItem> _items = new List<UC_FoodItem>();
  2. public List<UC_FoodItem> Items
  3. {
  4. get => _items;
  5. set => SetProperty(ref _items, value);
  6. }
  7.  
  8. protected void LoadFoods()
  9. {
  10. try
  11. {
  12. DataTable dt = _sqliteHelper.RunToDataSet("select * from Notes order by ID desc").Tables[];
  13.  
  14. var items = new List<UC_FoodItem>();
  15. foreach (DataRow row in dt.Rows)
  16. {
  17. UC_FoodItem foodItem = new UC_FoodItem();
  18. foodItem.lab_id.Content = row["ID"].ToString();
  19. foodItem.lab_foodName.Content = row["Title"].ToString();
  20. foodItem.lab_foodPrice.Content = row["Type"].ToString();
  21. foodItem.lab_foodIntro.Content = row["Content"].ToString();
  22.  
  23. items.Add(foodItem);
  24. }
  25.  
  26. Items = items;
  27. }
  28. catch (Exception ex)
  29. {
  30. Console.WriteLine(ex);
  31. MessageBox.Show($"载入数据出错:{ex.Message}");
  32. }
  33. }

ViewModel 中的绑定属性使用了 INotifyPropertyChanged 模式,此处是使用了 Prism 框架的写法(VM 继承了 BindableBase 类)。然后注意到这里新建了一个局部变量 items,填充完数据才赋值给 Items,这并不是多此一举,因为不这样的话,该属性的改变状态(PropertyChangedCallback)就无法触发。

最后但同样重要的是:既然这个用户控件这么简单,为什么不直接把里面的内容包括依赖属性写在使用的页面呢?因为那样的话,由于 MVVM

模式的原因,页面的 DataContext 已经指定为相关的 ViewModel 了,那么写在后台的依赖属性就找不到 DataContext 了。

WPF 用户控件的自定义依赖属性在 MVVM 模式下的使用备忘的更多相关文章

  1. 创建WPF用户控件

    wpf用户自定义控件和winform创建方法类似,这里先纠正一个误区,就是有很多人也是添加,然后新建,然后是新建用户控件库,但是为什么编译好生成后Debug目录下还是只有exe文件而没有dll文件呢? ...

  2. WPF Label控件在数据绑定Content属性变化触发TargetUpdated事件简单实现类似TextChanged 事件效果

    原文:WPF Label控件在数据绑定Content属性变化触发TargetUpdated事件简单实现类似TextChanged 事件效果   本以为Label也有TextChanged 事件,但在使 ...

  3. 【demo练习四】:WPF用户控件案例

    首先,新建vs中“用户控件(WPF)”,右键项目名 =>"添加"按钮 => 选择“新建项”. 然后选择“用户控件(WPF)” => 起名字 => 点击“添加 ...

  4. c# 用户控件,usercontrol,自定义控件属性

    1.C#用户控件的使用 2.拖动添加:画面上如需多个usercontrol,添加TableLayoutPanel,然后在工具箱中找到usercontrol,拖到相应框中 3.代码添加:主窗口中有多个T ...

  5. asp.net读取用户控件,自定义加载用户控件

    1.自定义加载用户控件 ceshi.aspx页面 <html> <body> <div id="divControls" runat="se ...

  6. WPF 用户控件嵌入网页

    WPF使用用户控件嵌入网页,直接使用WebBrowser或Frame会产生报错,报错信息如下: 1.使用WebBrowser,<WebBrowser Source="http://19 ...

  7. WPF用户控件库 嵌入外部(VLC)exe

    综合网上资源完成的自己的第一篇博客 ------------------------------------------------------------------------ 网上类似的贴子挺多 ...

  8. [Silverlight]监听指定控件(FrameworkElement)的依赖属性(DependencyProperty)的更改

    前言 转载请注明出处:http://www.cnblogs.com/ainijiutian 最近在silverlight项目使用Telerik的控件,遇到一个问题.就是使用RadBusyIndicat ...

  9. WPF之路——用户控件对比自定义控件UserControl VS CustomControl)

    将多个现有的控件组合成一个可重用的“组”. 由一个XAML文件和一个后台代码文件. 不能使用样式和模板. 继承自UserControl类. 自定义控件(扩展) 在现有的控件上进行扩展,增加一些新的属性 ...

随机推荐

  1. Golang 基础语法介绍及对比(二)

    传值与传参 Golong func main() { a := fmt.Println("a = ", a) // 应该输出 "a= 3" a1 := add1 ...

  2. Github库名命名规范

    必要性说明 由于迁移到Github上的项目越来越多,对项目的管理越来越困难.由于各项目命名具有随意性,用之代表git仓库名后就很难快速回忆起这个项目的相关细节,通常需要不断打开某个库才能有所了解.因此 ...

  3. 刷完欧拉计划中难度系数为5%的所有63道题,我学会了Rust中的哪些知识点?

    我为什么学Rust? 2019年6月18日,Facebook发布了数字货币Libra的技术白皮书,我也第一时间体验了一下它的智能合约编程语言MOVE,发现这个MOVE是用Rust编写的,看来想准确理解 ...

  4. WebStorm开发Vue自定义标签提示是未知标签解决办法

    打开 File -> Settings -> File Types 在右侧的窗口中找到Vue.js Template 并选中,在下面的窗口中添加 *.vue 即可解决问题. 修改后

  5. 《Interest Rate Risk Modeling》阅读笔记——第三章:拟合期限结构

    目录 第三章:拟合期限结构 思维导图 扩展 第三章:拟合期限结构 思维导图 扩展 NS 模型的变种

  6. PHP接口并发测试的方法

    PHP接口并发测试的方法 <pre> header('Content-type:text/html; Charset=utf-8'); $uri = "输入你的url" ...

  7. IntelliJ IDEA 创建java application

    1.打开IntelliJ IDEA,选择File——New——Project... 2.选择左侧的java,然后在右侧的Project SDK 中添加 java 环境目录,点击Next 3. 在下面的 ...

  8. Window与Document

    Window 表示一个包含DOM文档的窗口,其 document 属性指向窗口中载入的 DOM文档.使用 document.defaultView 属性可以获取指定文档所在窗口.window作为全局变 ...

  9. 聊聊Lambda架构

    定义 在数据分析场景中,我们可能会遇到这样的问题.例如,我们要做一个推荐系统,如果我们用批处理任务去做,一天或者一小时的推荐频次明显延迟太大.如果用流处理任务,虽然延迟的问题解决了,然而只用实时数据而 ...

  10. hadoop格式化:java.io.IOException: Incompatible clusterIDs in /home/lxh/hadoop/hdfs/data: namenode clusterID

    1 概述  解决hadoop启动hdfs时,datanode无法启动的问题.错误为: java.io.IOException: Incompatible clusterIDs in /home/lxh ...