Как расширить элемент управления в WPF, чтобы освободить место для сообщений об ошибках в ErrorTemplate? - PullRequest
4 голосов
/ 23 января 2009

У меня есть окно WPF, которое использует проверку. Я создал шаблон ошибки, который помещает красную рамку вокруг элемента, который не проходит проверку, и отображает сообщение об ошибке ниже. Это работает нормально, но сообщение об ошибке отображается поверх любых элементов управления под элементом управления с ошибкой. Насколько я могу судить, это происходит потому, что шаблон ошибок отображается на слое Adorner, который находится поверх всего остального. Что бы я хотел, чтобы все остальное переместилось вниз, чтобы освободить место для сообщения об ошибке. Есть ли способ сделать это? Кажется, что во всех примерах в Интернете используется всплывающая подсказка и простой индикатор, такой как звездочка или восклицательный знак, который не занимает много места.

Вот шаблон:

<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 Ответ

6 голосов
/ 07 апреля 2009

РЕДАКТИРОВАТЬ: Хорошо, я не уверен, что это лучшее решение (я надеюсь, что кто-то может предоставить лучшее), но здесь это идет:

Вместо использования Validation.ErrorTeplate, который будет представлять все визуальные элементы в AdornerLayer, вы можете добавить некоторые текстовые блоки и связать их с Validation.HasError и (Validation.Errors) [0] .ErrorContent, используя клиентский IValueConverter. преобразовать bool Validation.HasError в значение 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 ...

Удачи тебе! Если я найду лучшее решение, я обновлю это;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...