依赖属性至关于扩充了 WPF 标签的原有属性列表,并可使用 WPF 的绑定功能,可谓是十分方便的;用户控件则至关于代码重用的一种方式;以上几点分开来仍是比较好理解的,不过要用到MVVM 模式中,仍是要探索一番的。
html
咱们先新建一个用户控件(UC_FoodsPanel.xaml),里面放一个 StackPanel:sql
<UserControl x:Class="Note.UC_FoodsPanel" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <StackPanel x:Name="SpFoods" MinWidth="620"/> </UserControl>
而后在其后台添加依赖属性相关代码:express
C#app
public List<UC_FoodItem> Items { get => (List<UC_FoodItem>)GetValue(ItemsProperty); set => SetValue(ItemsProperty, value); } // Using a DependencyProperty as the backing store for Items. This enables animation, styling, binding, etc... public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(nameof(Items), typeof(List<UC_FoodItem>), typeof(UC_FoodsPanel), new PropertyMetadata(null, PropertyChangedCallback, null)); private static void PropertyChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args) { if (args.NewValue is List<UC_FoodItem> newValue) { try { var control = obj as UC_FoodsPanel; control.SpFoods.Children.Clear(); foreach (var item in newValue) { control.SpFoods.Children.Add(item); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); MessageBox.Show($"载入数据出错:{ex.Message}"); } } }
依赖属性相关内容可参考网上的《WPF 系列 —— 控件添加依赖属性 – 朝兮兮 – 博客园》 一文,添加依赖属性的方法为 —— 输入 propdp 再双击 tab 键。框架
上面代码中,咱们添加的依赖属性为 Items,是一个 UC_FoodItem 类的列表。关键在于属性改变时的回调函数 PropertyChangedCallback,其 obj 参数表明属性绑定的控件,即此处的 UC_FoodsPanel,args 参数中有 OldValue 和 NewValue,分别表明属性改变先后的值。此处即取改变后的值 —— 一个列表 —— 赋给用户控件中的 StackPanel。函数
这样以后,咱们在其它页面(Views\\MainWindowView.xaml)使用这个用户控件的时候,就可使用 Items 属性了:post
XHTMLspa
<note:UC_FoodsPanel Items="{Binding Items}"></note:UC_FoodsPanel>
而后在这个页面的 ViewModel 中(ViewModels\\MainWindowViewModel.cs)设置须要绑定的值:code
private List<UC_FoodItem> _items = new List<UC_FoodItem>(); public List<UC_FoodItem> Items { get => _items; set => SetProperty(ref _items, value); } protected void LoadFoods() { try { DataTable dt = _sqliteHelper.RunToDataSet("select * from Notes order by ID desc").Tables[0]; var items = new List<UC_FoodItem>(); foreach (DataRow row in dt.Rows) { UC_FoodItem foodItem = new UC_FoodItem(); foodItem.lab_id.Content = row["ID"].ToString(); foodItem.lab_foodName.Content = row["Title"].ToString(); foodItem.lab_foodPrice.Content = row["Type"].ToString(); foodItem.lab_foodIntro.Content = row["Content"].ToString(); items.Add(foodItem); } Items = items; } catch (Exception ex) { Console.WriteLine(ex); MessageBox.Show($"载入数据出错:{ex.Message}"); } }
ViewModel 中的绑定属性使用了 INotifyPropertyChanged 模式,此处是使用了 Prism 框架的写法(VM 继承了 BindableBase 类)。而后注意到这里新建了一个局部变量 items,填充完数据才赋值给 Items,这并非画蛇添足,由于不这样的话,该属性的改变状态(PropertyChangedCallback)就没法触发。orm
最后但一样重要的是:既然这个用户控件这么简单,为何不直接把里面的内容包括依赖属性写在使用的页面呢?由于那样的话,因为 MVVM
模式的缘由,页面的 DataContext 已经指定为相关的 ViewModel 了,那么写在后台的依赖属性就找不到 DataContext 了。