今天學習 ObservableObject的 三種綁定方式
- 普通屬性的綁定
和常用的綁定沒有區別;
1 private string _name; 2 3 public string Name 4 { 5 get => _name; 6 set => SetProperty(ref _name, value); 7 }
源碼
1 protected bool SetProperty<T>([NotNullIfNotNull("newValue")] ref T field, T newValue, [CallerMemberName] string? propertyName = null) 2 { 3 if (EqualityComparer<T>.Default.Equals(field, newValue)) 4 { 5 return false; 6 } 7 8 OnPropertyChanging(propertyName); 9 field = newValue; 10 OnPropertyChanged(propertyName); 11 return true; 12 }
可以看到是先判定了是否相等然后再通知!
- 數據代理屬性的綁定
1 public class User 2 { 3 public int Age { get; set; } 4 } 5 6 private User _user; 7 8 public int Age 9 { 10 get => _user.Age; 11 set => SetProperty(_user.Age, value, _user, (u, a) => u.Age = a); 12 }
可以看到 VM里面的屬性包裝了數據代理模型,通過委托來更新數據代理的數據;
源碼
1 protected bool SetProperty<TModel, T>(T oldValue, T newValue, TModel model, Action<TModel, T> callback, [CallerMemberName] string? propertyName = null) where TModel : class 2 { 3 if (EqualityComparer<T>.Default.Equals(oldValue, newValue)) 4 { 5 return false; 6 } 7 8 OnPropertyChanging(propertyName); 9 callback(model, newValue); 10 OnPropertyChanged(propertyName); 11 return true; 12 }
- Task屬性的綁定
1 private TaskNotifier<int> _count; 2 /// <summary> 3 /// 任務屬性綁定 4 /// </summary> 5 public Task<int> Count 6 { 7 get => _count; 8 set => SetPropertyAndNotifyOnCompletion(ref _count, value); 9 } 10 public ICommand RequestValueCmd { get; set; } 11 12 private async void RequestValue() 13 { 14 await Task.Delay(5000); 15 Count = Task.Run(() => 16 { 17 return 50; 18 }); 19 }
可以實現任務完成后自動刷新UI
源碼
1 protected bool SetPropertyAndNotifyOnCompletion([NotNull] ref TaskNotifier? taskNotifier, Task? newValue, [CallerMemberName] string? propertyName = null) 2 { 3 return SetPropertyAndNotifyOnCompletion(taskNotifier ?? (taskNotifier = new TaskNotifier()), newValue, delegate 4 { 5 }, propertyName); 6 }
后台代碼
1 using Microsoft.Toolkit.Mvvm.ComponentModel; 2 using Microsoft.Toolkit.Mvvm.Input; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 using System.Windows.Input; 9 10 namespace MVVMToolkit學習 11 { 12 public class ObservableObjectVM : ObservableObject 13 { 14 15 16 #region 普通屬性綁定 17 private string _name; 18 19 public string Name 20 { 21 get => _name; 22 set => SetProperty(ref _name, value); 23 } 24 #endregion 25 26 #region 數據代理綁定 27 private User _user; 28 29 public int Age 30 { 31 get => _user.Age; 32 set => SetProperty(_user.Age, value, _user, (u, a) => u.Age = a); 33 } 34 35 #endregion 36 37 38 39 public ObservableObjectVM() 40 { 41 Name = "嘯天"; 42 _user = new User(); 43 _user.Age = 18; 44 RequestValueCmd = new RelayCommand(RequestValue); 45 } 46 47 48 #region 綁定任務屬性 49 private TaskNotifier<int> _count; 50 /// <summary> 51 /// 任務屬性綁定 52 /// </summary> 53 public Task<int> Count 54 { 55 get => _count; 56 set => SetPropertyAndNotifyOnCompletion(ref _count, value); 57 } 58 public ICommand RequestValueCmd { get; set; } 59 60 private async void RequestValue() 61 { 62 await Task.Delay(5000); 63 Count = Task.Run(() => 64 { 65 return 50; 66 }); 67 } 68 #endregion 69 } 70 71 public class User 72 { 73 public int Age { get; set; } 74 } 75 }
前台代碼
1 <Window 2 x:Class="MVVMToolkit學習.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:MVVMToolkit學習" 7 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 8 Title="MainWindow" 9 Width="800" 10 Height="450" 11 d:DataContext="{d:DesignInstance Type=local:ObservableObjectVM}" 12 mc:Ignorable="d"> 13 <Grid> 14 <StackPanel 15 MinWidth="300" 16 HorizontalAlignment="Center" 17 Orientation="Vertical"> 18 <TextBlock Text="{Binding Name}" /> 19 <TextBox Text="{Binding Age}" /> 20 <TextBlock Text="{Binding Count.Result, UpdateSourceTrigger=PropertyChanged}" /> 21 <Button 22 Command="{Binding RequestValueCmd}" 23 Content="延時綁定" /> 24 </StackPanel> 25 </Grid> 26 </Window>