在固定位置显示 WPF 验证错误消息

Posted

技术标签:

【中文标题】在固定位置显示 WPF 验证错误消息【英文标题】:Show WPF validation error message in a fixed place 【发布时间】:2014-11-17 20:45:22 【问题描述】:

我运行了 WPF 验证(将 ValidationRules 添加到绑定中)并且使用模板我可以创建漂亮的装饰器。那里有很多帖子。

但我找不到在装饰控件之外的固定位置显示错误消息的方法,例如窗口一角的TextBlock,例如

我怎样才能做到这一点?我可以将所有验证错误消息绑定到我的DataContext(此处为 ViewModel)吗?


更新:感谢一个答案,我得到了部分工作。验证消息现在显示在另一个标签中。由于所有带有验证规则的文本框都是由代码动态创建的,因此绑定是通过这种方式完成的:

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

但验证消息仅转发到执行此代码的最后一个文本框的adornersite


我在这个小例子中重现了这个问题。

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>

当值等于字符串 "A" 时,类 RuleA 会产生验证错误。第二个文本框中的错误显示在 TextBlock 中,第一个错误不显示(而是使用默认模板并获得红色边框)。

它如何同时适用于两者?文本块不需要总结所有错误,而是显示第一个错误。

【问题讨论】:

【参考方案1】:

您可以将BindingGroupValidation.ValidationAdornerSiteValidation.ValidationAdornerSiteFor 属性结合使用。

This blog post 向您展示了如何执行此操作的示例。


<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)"

【讨论】:

感谢您的提示!使用Validation.ValidationAdornerSiteValidation.ValidationAdornerSiteFor,我将验证结果发送到另一个控件。但它只会为最后一个文本框中的错误分配一个..AdornerSite 我授予了这个答案,因为它对我有帮助,尽管我的解决方案朝着另一个方向发展。谢谢。请参阅接受的答案以了解我的最终解决方案。 谢谢,很高兴能帮上忙!【参考方案2】:

感谢http://www.scottlogic.com/blog/2008/11/28/using-bindinggroups-for-greater-control-over-input-validation.html,我能够在没有 ValidationAdornerSite 的情况下使用 BindingGroup 解决这个问题。

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

当然,对于更大的项目,附加属性可能会有所帮助。

【讨论】:

以上是关于在固定位置显示 WPF 验证错误消息的主要内容,如果未能解决你的问题,请参考以下文章

怎样在wpf下固定控件位置随界面的变化保持不动

在鼠标位置(鼠标左上角)显示 WPF 窗口的最佳方式是啥?

在反应本机模式上添加 UI 元素,例如固定位置上的按钮

gtk 固定窗口位置

opencv播放视频屏幕固定位置显示文字

Div与位置:固定不显示div内部位置:在Safari中绝对