如何在 WPF 中扩展控件以便为 ErrorTemplate 中的错误消息腾出空间?

Posted

技术标签:

【中文标题】如何在 WPF 中扩展控件以便为 ErrorTemplate 中的错误消息腾出空间?【英文标题】:How do I expand a control in WPF to make room for error messages in an ErrorTemplate? 【发布时间】:2009-01-23 19:33:30 【问题描述】:

我有一个使用验证的 WPF 窗口。我创建了一个错误模板,它在验证失败的元素周围放置了一个红色边框,并在下面显示错误消息。这可以正常工作,但错误消息会呈现在带有错误的控件下方的任何控件之上。我能说的最好的情况是,发生这种情况是因为错误模板呈现在装饰层上,装饰层位于其他一切之上。我希望发生的事情是让其他所有内容都向下移动以为错误消息腾出空间。有没有办法做到这一点?网络上的所有示例似乎都使用了工具提示,并使用了星号或感叹号之类的简单指示符,不会占用太多空间。

这是模板:

<ControlTemplate x:Key="ValidationErrorTemplate">
    <StackPanel>
        <Border BorderBrush="Red" BorderThickness="2" CornerRadius="2">
            <AdornedElementPlaceholder x:Name="placeholder"/>
        </Border>
        <TextBlock Foreground="Red" FontSize="10" Text="Binding ElementName=placeholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent, FallbackValue=Error!"></TextBlock>
    </StackPanel>
</ControlTemplate>

这里是使用模板的控件(我输入了一些,所以忽略任何语法错误):

<Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
  </Grid.RowDefinitions>
  <TextBox Name="Account" Grid.Row="0" Validation.ErrorTemplate="StaticResource ValidationErrorTemplate" Width="200">
    <TextBox.Text>
      <Binding Path="AccountNumber">
        <Binding.ValidationRules>
          <validators:RequiredValueValidationRule/>
          <validators:NumericValidationRule/>
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>
  </TextBox>
  <TextBox Name="Expiration" Grid.Row="1" Validation.ErrorTemplate="StaticResource ValidationErrorTemplate" Width="100"  Margin="0,2,5,2">
    <TextBox.Text>
      <Binding Path="ExpirationDate">
        <Binding.ValidationRules>
          <validators:ExpirationDateValidationRule/>
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>
  </TextBox>
</Grid>

【问题讨论】:

【参考方案1】:

编辑:好吧,我不肯定这是最好的解决方案(我当然希望有人能提供更好的解决方案),但它就是这样:

您可以添加一些文本块并将它们绑定到 Validation.HasError 和 (Validation.Errors)[0].ErrorContent,而不是使用将呈现 AdornerLayer 中的所有视觉效果的 Validation.ErrorTeplate,使用客户 IValueConverter将 Validation.HasError bool 转换为 Visibility 值。它看起来像下面这样:

Window1.cs:

<Window x:Class="WpfApplicationTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:local="clr-namespace:WpfApplicationTest"
    Title="Window1" Height="300" Width="300">
    <Grid Margin="10">
        <Grid.Resources>
            <!-- The person we are binding to -->
            <local:Person x:Key="charles" Name="Charles" Age="20" />
            <!-- The convert to use-->
            <local:HasErrorToVisibilityConverter x:Key="visibilityConverter" />
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <!-- The name -->
        <TextBox Name="NameTextBox" Grid.Row="0" Text="Binding Source=StaticResource charles, Path=Name, ValidatesOnDataErrors=true" />
        <TextBlock Grid.Row="1" 
                   Foreground="Red" 
                   Text="Binding ElementName=NameTextBox, Path=(Validation.Errors)[0].ErrorContent" 
                   Visibility="Binding ElementName=NameTextBox, Path=(Validation.HasError), Converter=StaticResource visibilityConverter" />

        <!-- The age -->
        <TextBox Name="AgeTextBox" Grid.Row="2" Text="Binding Source=StaticResource charles, Path=Age, ValidatesOnExceptions=true" />
        <TextBlock Grid.Row="3" 
                   Foreground="Red" 
                   Text="Binding ElementName=AgeTextBox, Path=(Validation.Errors)[0].ErrorContent" 
                   Visibility="Binding ElementName=AgeTextBox, Path=(Validation.HasError), Converter=StaticResource visibilityConverter" />
    </Grid>
</Window>

Person.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Text.RegularExpressions;

namespace WpfApplicationTest

    public class Person : IDataErrorInfo
    
        public string Name  get; set; 
        public int Age  get; set; 

        #region IDataErrorInfo Members

        string IDataErrorInfo.Error
        
            get  throw new NotImplementedException(); 
        

        string IDataErrorInfo.this[string columnName]
        
            get
            
                switch (columnName)
                
                    case ("Name"):
                        if (Regex.IsMatch(this.Name, "[^a-zA-Z ]"))
                        
                            return "Name may contain only letters and spaces.";
                        
                        else
                        
                            return null;
                        
                    default:
                        return null;
                
            
        

        #endregion
    

HasErrorToVisibilityConverter.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows;

namespace WpfApplicationTest

    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class HasErrorToVisibilityConverter : IValueConverter
    
        #region IValueConverter Members

        object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        
            bool hasError = (bool)value;
            return hasError ? Visibility.Visible : Visibility.Collapsed;
        

        object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        
            throw new NotImplementedException();
        

        #endregion
    

它的扩展性不如您可以在所有控件中引用的单个 ControlTemplate,但它是我找到的唯一解决方案。我感觉到你的痛苦——几乎我能找到的关于 WPF 验证主题的每个示例都非常简单,而且几乎总是使用“!”或 '*' 在控件前面,工具提示绑定到 (Validation.Errors)[0].ErrorContent...

祝你好运!如果我找到更好的解决方案,我会更新这个;)

【讨论】:

谢谢,希望对您有所帮助:)!如果你找到更好的方法,请告诉我。我尝试使用附加的依赖属性创建一个解决方案,但我不记得那是什么......

以上是关于如何在 WPF 中扩展控件以便为 ErrorTemplate 中的错误消息腾出空间?的主要内容,如果未能解决你的问题,请参考以下文章

将 WPF 控件设置为扩展以填充可用空间,仅此而已

WPF - 将位图转换为 ImageSource

如何相对缩放用户控件的大小?

如何在设计模式下调试 WPF 用户控件?

WPF中常用的表格控件都有哪些

wpf文件名显示在label中