WPF用户控件数据绑定异常:运行时无法更新Slider属性
问题:WPF用户控件依赖属性绑定不更新
尝试创建一个包含Slider的用户控件,用于绑定Slider的Value、SelectionStart和SelectionEnd属性。编译阶段设置的值能正常显示,但点击按钮修改ViewModel属性时,用户控件的依赖属性未触发更新,Slider状态无法同步。
主窗口XAML
xmlns:local="clr-namespace:DependencyPropertyExample" xmlns:uc="clr-namespace:DependencyPropertyExample.User_Controls" x:Name="MainWin" mc:Ignorable="d" Title="Slider Test" WindowStartupLocation="CenterScreen" Height="450" Width="200"> <Grid > <Grid.RowDefinitions> <RowDefinition Height="40" /> <RowDefinition Height="*" /> <RowDefinition Height="40" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100" /> <ColumnDefinition Width="100" /> </Grid.ColumnDefinitions> <Label Content="{Binding Path=Position, ElementName=userTest}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontWeight="Bold" /> <uc:UserTest x:Name="userTest" Position="{Binding Path=Pos}" Set_Title="THUMB" Set_SelStart="{Binding Path=Start}" Set_SelEnd="{Binding Path=End}" Grid.Row="1" Margin="0,0,0,20" /> <Label Content="{Binding Value, ElementName=Slider1, StringFormat=\{0:D0\}}" Grid.Column="1" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontWeight="Bold" /> <Slider x:Name="Slider1" Value="50" IsSelectionRangeEnabled="True" SelectionStart="10" SelectionEnd="90" Grid.Row="1" Grid.Column="1" Orientation="Vertical" HorizontalAlignment="Center" Maximum="100" SmallChange="1" Margin="0,45,0,24" /> <Button x:Name="btn_Press" Content="Press" Grid.Row="2" Margin="10,10,10,10" Click="btn_Press_Click" /> </Grid>
主窗口后台代码
public static event PropertyChangedEventHandler PropertyChanged; public static void OnPropertyChanged([CallerMemberName] string? propertyname = null) { PropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyname)); } private double _start { get; set; } public double Start { get { return _start; } set { _start = value; OnPropertyChanged("Start"); } } private double _end { get; set; } public double End { get { return _end; } set { _end = value; OnPropertyChanged("End"); } } private double _pos { get; set; } public double Pos { get { return _pos; } set { _pos = value; OnPropertyChanged("Pos"); } } public MainWindow() { InitializeComponent(); DataContext = this; Start = 10; End = 90; Pos = 50; } private void btn_Press_Click(object sender, RoutedEventArgs e) { Start = 30; End = 60; Pos = 70; } }
UserTest用户控件XAML
<Grid> <Grid.RowDefinitions> <RowDefinition Height="40" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Label x:Name="title" Content="{Binding Set_Title, ElementName=SliderRoot}" Grid.Row="0" Grid.Column="0" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontWeight="Bold" /> <Slider x:Name="Digit_Slider" Orientation="Vertical" Value="{Binding Position, RelativeSource={RelativeSource AncestorType=UserControl}}" SelectionStart="{Binding Set_SelStart, RelativeSource={RelativeSource AncestorType=UserControl}}" SelectionEnd="{Binding Set_SelEnd, RelativeSource={RelativeSource AncestorType=UserControl}}" Grid.Row="1" Grid.Column="0" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="0,5,0,5" Maximum="100" HorizontalAlignment="Center" IsSelectionRangeEnabled="True" RenderTransformOrigin="0.5,0.5" IsDirectionReversed="True" Cursor="Hand" ValueChanged="Digit_Slider_ValueChanged" /> </Grid>
UserTest用户控件后台代码
public static readonly DependencyProperty Title_Property = DependencyProperty.Register("Set_Title", typeof(string), typeof(UserTest), new PropertyMetadata(string.Empty)); public static DependencyProperty SelStart_Property = DependencyProperty.Register("Set_SelStart", typeof(double), typeof(UserTest), new PropertyMetadata(0.0, OnSelStart_Changed)); public static readonly DependencyProperty SelEnd_Property = DependencyProperty.Register("Set_SelEnd", typeof(double), typeof(UserTest), new PropertyMetadata(0.0, OnSelEnd_Changed)); public static DependencyProperty Pos_Property = DependencyProperty.Register("Position", typeof(double), typeof(UserTest), new PropertyMetadata(0.0, OnPosition_Changed)); private static void OnSelStart_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { var User = d as UserTest; User.Digit_Slider.SelectionStart = (double)e.NewValue; } private static void OnSelEnd_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { var User = d as UserTest; User.Digit_Slider.SelectionEnd = (double)e.NewValue; } private static void OnPosition_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { var User = d as UserTest; User.Digit_Slider.Value = (double)e.NewValue; } // Set TITLE (string) property of Slider public string Set_Title { get { return (string)GetValue(Title_Property); } set { SetValue(Title_Property, value); } } // Set SELECTION START (double) property of Slider // MODE = 1 Way (Write) public double Set_SelStart { get { return (double)GetValue(SelStart_Property); } set { SetValue(SelStart_Property, value); } } // Get VALUE (double) property of Slider // MODE = 2 Way (Read / Write) public double Position { get { return (double)GetValue(Pos_Property); } set { SetValue(Pos_Property, value); } } // Set SELECTION END (double) property of Slider public double Set_SelEnd { get { return (double)GetValue(SelEnd_Property); } set { SetValue(SelEnd_Property, value); } } #endregion DEPENDENCY_PROPERTIES public UserTest() { InitializeComponent(); }
解决方案
问题出在主窗口的PropertyChanged事件定义为静态,WPF的数据绑定系统无法正确订阅静态事件来更新UI绑定。将事件和触发方法改为非静态即可:
修改主窗口的事件和方法:
// 去掉static修饰符 public event PropertyChangedEventHandler PropertyChanged; // 去掉static修饰符 public void OnPropertyChanged([CallerMemberName] string? propertyname = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname)); }
补充说明:
- WPF绑定系统默认监听的是实例级的
INotifyPropertyChanged事件,静态事件无法被绑定引擎正确处理,导致属性更新时无法通知到绑定目标(用户控件的依赖属性)。 - 用户控件中通过依赖属性回调直接设置Slider属性的逻辑是正常的,只要依赖属性能接收到绑定源的更新值,就能同步到Slider上。
内容的提问来源于stack exchange,提问作者user3119168
相关产品推荐
相关产品推荐

