样式中WPF数据绑定的时序问题

问题描述 投票:0回答:1

我想在 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
永远不会被执行。

wpf validation data-binding
1个回答
0
投票

如果我使用

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

© www.soinside.com 2019 - 2024. All rights reserved.