WPF Toolkit TimePicker手动输入时间不更新Value,仅失焦触发PropertyChanged
解决WPF Toolkit TimePicker手动输入不触发PropertyChanged的问题
我之前也碰到过一模一样的问题——用小键盘手动输入时间时,ResTime的绑定完全没反应,PropertyChanged事件也不触发。这其实是因为Xceed的TimePicker控件内部逻辑的问题:默认情况下,手动输入文本时,控件不会即时把输入内容解析并同步到Value属性,哪怕你在绑定里设置了UpdateSourceTrigger=PropertyChanged。
下面是几个亲测有效的解决方案:
方案一:在TextChanged事件里手动更新绑定
既然控件自己不触发,我们就手动帮它触发绑定源更新。在你已经绑定的TimePicker_TextChanged事件里添加以下代码:
private void TimePicker_TextChanged(object sender, TextChangedEventArgs e) { var timePicker = sender as Xceed.Wpf.Toolkit.TimePicker; if (timePicker == null) return; // 获取TimePicker内部的TextBox控件(默认模板里的名称是PART_TextBox) var textBox = timePicker.Template.FindName("PART_TextBox", timePicker) as TextBox; if (textBox != null) { // 先更新TextBox的Text绑定源,再同步Value属性的绑定 textBox.GetBindingExpression(TextBox.TextProperty)?.UpdateSource(); timePicker.GetBindingExpression(TimePicker.ValueProperty)?.UpdateSource(); } }
这个方法最直接,不需要修改模板或者额外写类,适合快速解决问题。
方案二:自定义Style修改内部TextBox的绑定
如果不想在后台写事件逻辑,可以通过自定义Style来修改TimePicker内部TextBox的Text绑定,把它的UpdateSourceTrigger设为PropertyChanged:
<Window.Resources> <Style TargetType="{x:Type xctk:TimePicker}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type xctk:TimePicker}"> <!-- 这里复制TimePicker的默认模板代码,找到PART_TextBox并修改其Text绑定 --> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <Grid> <TextBox x:Name="PART_TextBox" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="3"/> <ToggleButton x:Name="PART_ToggleButton" HorizontalAlignment="Right" VerticalAlignment="Center" IsChecked="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"/> </Grid> </Border> <!-- 其他默认模板元素(比如下拉面板)可以直接复制原模板的代码 --> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources>
注意:需要确保复制的模板和你当前使用的Toolkit版本的默认模板一致,不然可能会丢失一些功能。如果觉得复制麻烦,方案一其实更省心。
方案三:用附加属性实现通用解决方案
如果你的项目里有多个TimePicker需要解决这个问题,可以写一个附加属性来封装逻辑,避免重复代码:
public static class TimePickerSyncHelper { public static readonly DependencyProperty SyncValueOnTextChangedProperty = DependencyProperty.RegisterAttached( "SyncValueOnTextChanged", typeof(bool), typeof(TimePickerSyncHelper), new PropertyMetadata(false, OnSyncValueOnTextChangedChanged)); public static bool GetSyncValueOnTextChanged(DependencyObject obj) { return (bool)obj.GetValue(SyncValueOnTextChangedProperty); } public static void SetSyncValueOnTextChanged(DependencyObject obj, bool value) { obj.SetValue(SyncValueOnTextChangedProperty, value); } private static void OnSyncValueOnTextChangedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var timePicker = d as Xceed.Wpf.Toolkit.TimePicker; if (timePicker == null) return; if ((bool)e.NewValue) { timePicker.Loaded += TimePicker_Loaded; } else { timePicker.Loaded -= TimePicker_Loaded; var textBox = timePicker.Template.FindName("PART_TextBox", timePicker) as TextBox; textBox?.TextChanged -= TextBox_TextChanged; } } private static void TimePicker_Loaded(object sender, RoutedEventArgs e) { var timePicker = sender as Xceed.Wpf.Toolkit.TimePicker; var textBox = timePicker.Template.FindName("PART_TextBox", timePicker) as TextBox; textBox?.TextChanged += TextBox_TextChanged; } private static void TextBox_TextChanged(object sender, TextChangedEventArgs e) { var textBox = sender as TextBox; var timePicker = textBox.TemplatedParent as Xceed.Wpf.Toolkit.TimePicker; timePicker?.GetBindingExpression(TimePicker.ValueProperty)?.UpdateSource(); } }
然后在XAML里直接给TimePicker加上这个附加属性就行:
<xctk:TimePicker Name="timePicker" local:TimePickerSyncHelper.SyncValueOnTextChanged="True" StartTime="{Binding MpStartTime,UpdateSourceTrigger=PropertyChanged}" EndTime="{Binding MpEndTime,UpdateSourceTrigger=PropertyChanged}" Value="{Binding ResTime,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Format="Custom" FormatString="hh:mm tt"/>
方案四:升级Toolkit版本
这个问题可能是旧版本Xceed WPF Toolkit的bug,你可以尝试从NuGet安装最新版本的Xceed.Wpf.Toolkit包,看看官方是否已经修复了这个手动输入不更新绑定的问题。
内容的提问来源于stack exchange,提问作者Vishnu Babu
相关产品推荐
相关产品推荐

