0

I wanted to have data validation at once in WPF binding so I used PropertyChanged at UpdateSourceTrigger. At the same time I wanted to detect LostFocus, this is the time I modify the DB. Moreover, I needed this in a DataGrid. I solved this problem by introducing a temp property. I use the PropertyChanged at the TempProperty and used event handler at LostFocus. The event handler copied the TempProperty to the MainProperty and triggered the DB change. This method worked.

I wanted to use Behavior instead of event handler. This is the Behavior

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);
    }
}

Setting Behaviors in style is not easy. But this solution works for me.

Now the solution is this

<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 copies the TempProperty to the MainProperty. There is a slight problem Visual Studio says there is a Binding problem at MyCommand though the binding works. The binding error says the DataContext is null, it should be the object behind the selected row. MyCommand is in that object and it is executed as expected. It seems the Binding is evaulated before the DataContext is set, that is why an error is shown. Later the DataContext is set and the binding is reevaulated (?), that is why MyCommand works.

This seems to be a minor issue but grows if I want to build on this solution.

<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 contains an additional dependency property the FinalizeCommand which is used in the TextBoxLostFocusBehavior. This additonal level of indirectcy is needed so I do not need to create a new style for each DataGridTextColumn where I want the validation. Now Visual Studio indicates binding error at LostFocusCommand and FinalizeCommand as well. The problem is again the DataContext is null. I do not know if it is related but the OnDetaching is never executed.

2
  • So your binding works at runtime but Visual Studio doesn't detect the DataContext at design time? Not much you can do about this I am afraid.
    – mm8
    Commented May 7 at 18:27
  • @mm8 The xaml binding error is shown at runtime. But a little time after the error is indicated the DataContext is set properly so the binding works now. I do not know how to make sure that the DataContext is set before the Binding is evaulated. Commented May 7 at 19:21

1 Answer 1

0

If I use DataGridTemplateColumn instead of DataGridTextColumn then we do not have to set the TextBoxLostFocusBehavior in style, so there is no binding problem.

The DataTemplate which contains TextBox with 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>

Using the template

            <DataGridTemplateColumn Width="300"
                                    CellEditingTemplate="{StaticResource BalanceFilenameValidationTemplate}"
                                    CellTemplate="{StaticResource BalanceFilenameValidationTemplate}"
                                    Header="{x:Static r:Resource.BalanceFilenameTemplate}" />

I have report the wpf bug.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.