建立一個ViewModel並自定義屬性取代UserControl中的自定義屬性
ViewModel.cs:
class ViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private int _labelValue; public int LabelValue { get => _labelValue; set { _labelValue = value; Console.WriteLine(_labelValue); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LabelValue")); } } }
INotifyPropertyChanged主要作用是通蜘UI介面對應的屬性值有改變了。
MainWindow中Slider的Value<=>ViewModel的LabelValue<=>UserControl中Label3的Content
在MainWindow要綁定ViewModel屬性方式跟綁定UserControl的屬性一樣,
分為使用code綁定或是在XAML內綁定。
MainWindow使用code綁定ViewModel屬性:
public MainWindow() { InitializeComponent(); DataContext = new ViewModel(); Slider1.SetBinding(Slider.ValueProperty, new Binding("LabelValue")); }
MainWindow的XAML內綁定ViewModel屬性:
<Window x:Class="WpfApp3.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp3" mc:Ignorable="d" Title="MainWindow" Height="400" Width="300"> <Window.DataContext> <local:ViewModel/> </Window.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Slider x:Name="Slider1" Grid.Column="1" HorizontalAlignment="Center" Grid.Row="1" VerticalAlignment="Center" Width="250" ValueChanged="Slider1_ValueChanged" SmallChange="1" Maximum="100" Value="{Binding LabelValue}"/> <local:UserControl1 x:Name="UserControl_Labels" HorizontalAlignment="Center" VerticalAlignment="Center" LabelValue1="{Binding ElementName=Slider1, Path=Value}" LabelValue2="{Binding ElementName=Slider1, Path=Value}"/> </Grid> </Window>
以上這兩個方式是等效的。
設定DataContext為ViewModel,然後將Slider1的Value與ViewModel的LabelValue綁定。
UserControl用code做綁定:
public partial class UserControl1 : UserControl { public UserControl1() { InitializeComponent(); Label1.SetBinding(ContentProperty, new Binding(nameof(LabelValue1)) { Source = this }); Label3.SetBinding(ContentProperty, new Binding() {Path = new PropertyPath(nameof(ViewModel.LabelValue))}); //這邊不需設定DataContext,會自動參考到ViewModel的LabelValue //但如果在這或是XAML內有設定全域性的DataContext,則這裡的綁定會失效。 } public object LabelValue1 { get => GetValue(LabelValue1Property); set => SetValue(LabelValue1Property, value); } public static readonly DependencyProperty LabelValue1Property = DependencyProperty.Register("LabelValue1", typeof(object), typeof(UserControl1)); public object LabelValue2 { get => (object)GetValue(LabelValue2Property); set => SetValue(LabelValue2Property, value); } public static readonly DependencyProperty LabelValue2Property = DependencyProperty.Register("LabelValue2", typeof(object), typeof(UserControl1), new PropertyMetadata(3.0)); }
UserControl的XAML內做綁定:
<UserControl x:Class="WpfApp3.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp3"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label x:Name="Label1"
Content="Label1"
HorizontalAlignment="Stretch"
Grid.Row="0"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
FontSize="36"
Background="#FFAA2525"
Foreground="#FFFBF8F6"/>
<Label x:Name="Label2"
d:DataContext="{d:DesignInstance Type=local:UserControl1}"
DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:UserControl1}}"
Content="{Binding LabelValue2}"
HorizontalAlignment="Stretch"
Grid.Row="1"
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
FontSize="36"
Background="#FF60B646"
Foreground="#FFFBF8F6"/>
<Label x:Name="Label3"
d:DataContext="{d:DesignInstance Type=local:ViewModel}"
Content="{Binding LabelValue}"
HorizontalAlignment="Stretch"
Grid.Row="2"
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
FontSize="36"
Background="#FF28389C"
Foreground="#FFFBF8F6">
</Label>
</Grid>
</UserControl>
這比較不一樣的是 d:DataContext="{d:DesignInstance Type=local:UserControl1}"
以及d:DataContext="{d:DesignInstance Type=local:ViewModel}",
這兩行的效果是在設計階段引用參考實例,
在UI上顯示綁定後的值,如果是數值就顯示數字、如果是物件就顯示物件名稱。
PS.Label3不需設定DataContext。
DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:UserControl1}}"
屬於區域性的DataContext設定,如果設定全域性的DataContext會影響Label3綁定ViewModel的LabelValue。
PS.Label2綁定UserControl的LabelValue2,而Label3綁定的是ViewModel的LabelValue。
簡單說就是Label2是綁定自身屬性,Label3是綁定其他物件的屬性。
如果是參考單一ViewModel屬性或是自身屬性的話,只需設定全域性的DataContext。