代码之家  ›  专栏  ›  技术社区  ›  Eddie Deyo

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

  •  4
  • Eddie Deyo  · 技术社区  · 17 年前

    我有一个使用验证的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 回复  |  直到 17 年前
        1
  •  6
  •   Charles    17 年前

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

    您可以添加一些文本块并将它们绑定到Validation.HasError和(Validation.Errors)[0].ErrorContent,而不是使用Validation.ErrorTeplate(它将显示AdornerLayer中的所有视觉效果),使用客户IValueConverter将Validation.HasError bool转换为可见性值。它看起来类似于以下内容:

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

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

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