Show WPF validation error message in fixed location

I got WPF authentication (added ValidationRulesto the binding) and using the template I can create nice decorations. There are a lot of messages.

But I can’t find a way to display the error message outside the decorated control in a fixed place, for example, TextBlockin the corner of the window, for example.

How could I achieve this? Can I link all my validation error messages to mine DataContext(ViewModel here)?


Update: thanks to the answer, I got part of the job. Verification messages now appear on a different label. Since all text fields with their validation rules are created on the fly along the code, the binding for this is performed as follows:

Binding bindSite = new Binding();
bindSite.Source = this.validationErrorDisplayLabel;
BindingOperations.SetBinding(textBox, Validation.ValidationAdornerSiteProperty, bindSite);

But verification messages are only sent to adornersitefor the last text field for which this code was executed.


I reproduced the problem in this small example.

XAML:

<Grid>
    <TextBox 
        Validation.ValidationAdornerSite="{Binding ElementName=ErrorDisplay}"
        HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120">
        <TextBox.Text>
            <Binding>
                <Binding.Path>Box1</Binding.Path>
                <Binding.ValidationRules>
                    <local:RuleA />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
    <TextBox 
        Validation.ValidationAdornerSite="{Binding ElementName=ErrorDisplay}"
        HorizontalAlignment="Left" Height="23" Margin="10,38,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120">
        <TextBox.Text>
            <Binding>
                <Binding.Path>Box2</Binding.Path>
                <Binding.ValidationRules>
                    <local:RuleA />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
    <TextBlock 
        x:Name="ErrorDisplay"
        Background="AntiqueWhite"
        Foreground="Red"
        Text="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.ValidationAdornerSiteFor).(Validation.Errors)[0].ErrorContent}"
        HorizontalAlignment="Left" Margin="230,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="2.218,-4.577" Width="177" Height="51"/>
</Grid>

The class RuleAgenerates a validation error when the value is equal to a string "A". Errors in the second text field are displayed in the TextBlock, errors of the first are not (instead, it uses the default template and gets a red frame).

How can it work for both? The text block does not need to summarize all errors, but display the very first error.

+4
source share
2 answers

http://www.scottlogic.com/blog/2008/11/28/using-bindinggroups-for-greater-control-over-input-validation.html BindingGroup ValidationAdornerSite.

<Window x:Class="BindingAndValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BindingAndValidation"
        Title="Binding and Validation" Height="110" Width="425"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        >
    <Grid x:Name="RootElement">
        <Grid.Resources>
            <Style TargetType="{x:Type TextBox}">
                <Style.Triggers>
                    <Trigger Property="Validation.HasError" Value="true">
                        <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Grid.Resources>
        <Grid.BindingGroup>
            <BindingGroup Name="LocalBindingGroup">
                <BindingGroup.ValidationRules>
                    <local:RuleGroup />
                </BindingGroup.ValidationRules>
            </BindingGroup>
        </Grid.BindingGroup>
        <TextBox 
            HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" LostFocus="TextBox_LostFocus">
            <TextBox.Text>
                <Binding>
                    <Binding.Path>Box1</Binding.Path>
                    <Binding.BindingGroupName>LocalBindingGroup</Binding.BindingGroupName>
                    <Binding.ValidationRules>
                        <local:RuleA />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <TextBox 
            HorizontalAlignment="Left" Height="23" Margin="10,38,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120">
            <TextBox.Text>
                <Binding>
                    <Binding.Path>Box2</Binding.Path>
                    <Binding.BindingGroupName>LocalBindingGroup</Binding.BindingGroupName>
                    <Binding.ValidationRules>
                        <local:RuleA />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <ItemsControl ItemsSource="{Binding Path=(Validation.Errors), ElementName=RootElement}" MinWidth="100" MinHeight="16" Margin="230,10,0,0" Background="AntiqueWhite" Foreground="Red">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Label Foreground="Red" Content="{Binding Path=ErrorContent}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <Button Content="Button" HorizontalAlignment="Left" Margin="150,0,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" />
    </Grid>
</Window>

CommitEdit. , , , LostFocus

    private void TextBox_LostFocus(object sender, RoutedEventArgs e)
    {
        this.RootElement.BindingGroup.CommitEdit();
    }

, .

+3

BindingGroup Validation.ValidationAdornerSite Validation.ValidationAdornerSiteFor.

, .


<StackPanel x:Name="FormRoot"
            Validation.ValidationAdornerSite="{Binding ElementName=ErrorDisplay}">
  <FrameworkElement.BindingGroup>
    <BindingGroup Name="FormBindingGroup" />
  </FrameworkElement.BindingGroup>

  <TextBox>
    <TextBox.Text>
      <Binding BindingGroupName="FormBindingGroup"
               UpdateSourceTrigger="LostFocus"
               Path="Box1">
        <Binding.ValidationRules>
          <l:RuleA />
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>
  </TextBox>

<TextBox>
    <TextBox.Text>
      <Binding BindingGroupName="FormBindingGroup"
               UpdateSourceTrigger="LostFocus"
               Path="Box2">
        <Binding.ValidationRules>
          <l:RuleA />
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>
  </TextBox>

  <ItemsControl x:Name="ErrorDisplay"
                Background="AntiqueWhite"
                Foreground="Red"
                ItemsSource="{Binding RelativeSource={RelativeSource Self},
                                      Path=(Validation.ValidationAdornerSiteFor).(Validation.Errors)}"
                DisplayMemberPath="ErrorContent" />
</StackPanel>

, UpdateSourceTrigger PropertyChanged. , ValidationAdornerSite; ErrorDisplay BindingGroup:

ItemsSource="{Binding ElementName=FormRoot, Path=(Validation.Errors)}"
+6

All Articles