依賴屬性至關於擴充了 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 了。