我想在 WPF 绑定中立即进行数据验证,因此我在 UpdateSourceTrigger 中使用了 PropertyChanged。同时我想检测LostFocus,这是我修改DB的时间。此外,我需要这个在
DataGrid
中。我通过引入 temp 属性解决了这个问题。我在 PropertyChanged
处使用 TempProperty
,并在 LostFocus
处使用事件处理程序。事件处理程序将 TempProperty
复制到 MainProperty
并触发数据库更改。这个方法有效。
我想使用行为而不是事件处理程序。这就是行为
public class TextBoxLostFocusBehavior : Behavior<TextBox>
{
public static readonly DependencyProperty LostFocusCommandProperty =
DependencyProperty.Register("LostFocusCommand", typeof(ICommand),
typeof(TextBoxLostFocusBehavior), new PropertyMetadata(null));
public ICommand LostFocusCommand
{
get { return (ICommand)GetValue(LostFocusCommandProperty); }
set { SetValue(LostFocusCommandProperty, value); }
}
protected override void OnAttached() => AssociatedObject.LostFocus += AssociatedObject_LostFocus;
protected override void OnDetaching() => AssociatedObject.LostFocus -= AssociatedObject_LostFocus;
private void AssociatedObject_LostFocus(object sender, RoutedEventArgs e)
{
if (LostFocusCommand is not null && LostFocusCommand.CanExecute(null))
LostFocusCommand.Execute(null);
}
}
以风格设置行为并不容易。但是这个解决方案对我有用。
现在解决方案是这样的
<DataGridTextColumn
Binding="{Binding TempBalanceFilenameTemplate, TargetNullValue='', ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
ElementStyle="{StaticResource TextAlignmentRightElementStyle}"
Header="{x:Static r:Resource.BalanceFilenameTemplate}">
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="{x:Type TextBox}">
<Setter Property="hh:BehaviorInStyleAttacher.Behaviors">
<Setter.Value>
<collections:ArrayList>
<hhb:TextBoxLostFocusBehavior LostFocusCommand="{Binding MyCommand}" />
</collections:ArrayList>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
MyCommand
将 TempProperty
复制到 MainProperty
。尽管绑定有效,但 Visual Studio 表示存在一个小问题 MyCommand
处存在绑定问题。绑定错误表明 DataContext 为 null,它应该是所选行后面的对象。 MyCommand
位于该对象中,并且按预期执行。似乎在设置 DataContext 之前评估了 Binding,这就是显示错误的原因。后来设置了 DataContext 并重新评估了绑定(?),这就是 MyCommand
起作用的原因。
这似乎是一个小问题,但如果我想在此解决方案的基础上进行构建,问题就会变得越来越严重。
<hhd:DataGridTextColumnEx Width="300"
Binding="{Binding TempBalanceFilenameTemplate, TargetNullValue='', ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
ElementStyle="{StaticResource TextAlignmentRightElementStyle}"
FinalizeCommand="{Binding MyCommand}"
Header="{x:Static r:Resource.BalanceFilenameTemplate}">
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="{x:Type TextBox}">
<Setter Property="hha:BehaviorInStyleAttacher.Behaviors">
<Setter.Value>
<collections:ArrayList>
<hhb:TextBoxLostFocusBehavior LostFocusCommand="{Binding FinalizeCommand, RelativeSource={RelativeSource AncestorType={x:Type hhd:DataGridTextColumnEx}}}" />
</collections:ArrayList>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.EditingElementStyle>
</hhd:DataGridTextColumnEx>
DataGridTextColumnEx
包含一个额外的依赖属性 FinalizeCommand
,它在 TextBoxLostFocusBehavior
中使用。需要这种额外的间接级别,因此我不需要为每个需要验证的DataGridTextColumn
创建新样式。现在,Visual Studio 也在 LostFocusCommand
和 FinalizeCommand
处指示绑定错误。问题又是 DataContext
为空。我不知道它是否相关,但是 OnDetaching
永远不会被执行。
如果我使用
DataGridTemplateColumn
而不是DataGridTextColumn
,那么我们就不必在样式中设置TextBoxLostFocusBehavior
,因此不存在绑定问题。
包含
TextBox
和 TextBoxLostFocusBehavior
的数据模板
<DataTemplate x:Key="BalanceFilenameValidationTemplate">
<TextBox Text="{Binding TempBalanceFilenameTemplate, TargetNullValue='', ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" Margin="0" BorderThickness="0">
<i:Interaction.Behaviors>
<hhb:TextBoxLostFocusBehavior LostFocusCommand="{Binding SetBalanceFilenameTemplateCommand}"/>
</i:Interaction.Behaviors>
</TextBox>
</DataTemplate>
使用模板
<DataGridTemplateColumn Width="300"
CellEditingTemplate="{StaticResource BalanceFilenameValidationTemplate}"
CellTemplate="{StaticResource BalanceFilenameValidationTemplate}"
Header="{x:Static r:Resource.BalanceFilenameTemplate}" />
我已经报告了 wpf bug。