Шаблон MVVM, IDataErrorInfo и Binding для отображения ошибки? - PullRequest
5 голосов
/ 14 июля 2009

В MSDN Magazine есть хорошая статья о MVVM, и они связывают ошибку проверки в Xaml с Validation.ErrorTemplate="{x:Null}". Я не понимаю, почему и как они могут отображать из IDataErrorInfo ошибку? Кто-нибудь может подсказать мне, как вывести сообщение об ошибке на экран с помощью подхода MVVM?

Ответы [ 4 ]

16 голосов
/ 14 июля 2009

При привязке к объекту, который поддерживает IDataErrorInfo, следует учитывать несколько особенностей класса привязки WPF:

  1. ValidatesOnDataErrors должно быть True. Это указывает WPF искать и использовать интерфейс IDataError для базового объекта.

  2. Присоединенное свойство Validation.HasError будет установлено в true для целевого объекта, если интерфейс IDataError исходного объекта сообщил о проблеме проверки. Затем вы можете использовать это свойство с триггером, чтобы изменить всплывающую подсказку элемента управления для отображения сообщения об ошибке проверки (я делаю это в моем текущем проекте, и конечный пользователь любит его)

  3. Вложенное свойство Validation.Errors будет содержать перечисление любых ошибок ValidationResult, возникших в результате последней попытки проверки. Если вы используете подход всплывающей подсказки, используйте IValueConverter для извлечения только первого элемента ... в противном случае вы столкнетесь с ошибками связывания для отображения самого сообщения об ошибке.

  4. Класс привязки предоставляет NotifyOnValidationError, которая при значении True приведет к тому, что перенаправленные события будут пузыриться из привязанного элемента управления каждый раз, когда изменяется состояние правила проверки. Это полезно, если вы хотите реализовать обработчик событий в контейнере связанных элементов управления, а затем добавить и удалить сообщения проверки в / из списка.

В MSDN есть примеры для выполнения обоих стилей обратной связи (всплывающие подсказки и список), но я вставлю ниже код, который я использовал, чтобы реализовать отзыв всплывающей подсказки для моих DataGridCells и TextBoxes ...

Стиль DataGridCell:

   <Style TargetType="{x:Type dg:DataGridCell}"
           x:Key="DataGridCellStyle">

      <Setter Property="ToolTip"
              Value="{Binding Path=Column.(ToolTipService.ToolTip),RelativeSource={RelativeSource Self}}" />

      <Style.Triggers>
        <Trigger Property="Validation.HasError"
                 Value="True">
          <Setter Property="ToolTip"
                  Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors), Converter={StaticResource ErrorContentConverter}}" />
        </Trigger>
      </Style.Triggers>

    </Style>

Стиль TextBox:

     <Style x:Key="ValidatableTextBoxStyle" TargetType="TextBox">
  <!--When the control is not in error, set the tooltip to match the AutomationProperties.HelpText attached property-->
  <Setter Property="ToolTip"
          Value="{Binding RelativeSource={RelativeSource Mode=Self},Path=(AutomationProperties.HelpText)}" />

          <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
              <Setter Property="ToolTip"
                      Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=(Validation.Errors)[0].ErrorContent}" />
            </Trigger>
          </Style.Triggers>
        </Style>

ErrorContentConverter (для получения первого сообщения об ошибке проверки для всплывающей подсказки):

Imports System.Collections.ObjectModel

Namespace Converters

    <ValueConversion(GetType(ReadOnlyObservableCollection(Of ValidationError)), GetType(String))> _
    Public Class ErrorContentConverter
        Implements IValueConverter

        Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
            Dim errors As ReadOnlyObservableCollection(Of ValidationError) = TryCast(value, ReadOnlyObservableCollection(Of ValidationError))
            If errors IsNot Nothing Then
                If errors.Count > 0 Then
                    Return errors(0).ErrorContent
                End If
            End If
            Return String.Empty
        End Function

        Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
            Throw New NotImplementedException()
        End Function

    End Class

End Namespace

... и, наконец, пример использования стиля в текстовом поле:

    <TextBox Text="{Binding Path=EstimatedUnits,ValidatesOnDataErrors=True,NotifyOnValidationError=True}"
             Style="{StaticResource ValidatableTextBoxStyle}"
             AutomationProperties.HelpText="The number of units which are likely to sell in 1 year." />
6 голосов
/ 14 июля 2009

Я смотрел на тот же образец всего несколько минут назад. Ваше предположение верно. В этом примере кода они удалили ErrorTemplate по умолчанию из элемента управления TextBox, чтобы он не показывал красный прямоугольник. Вместо использования ErrorTemplate они создают ContentProvider с содержимым, связанным с ошибкой проверки определенного текстового поля.

0 голосов
/ 13 октября 2014

Вот код, который я использовал для отображения ошибки в подсказке или маленьком пузырьке рядом с элементом управления.

  1. Определение стиля.

    <Style x:Key="TextBoxValidationStyle" 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>
    
    <Style x:Key="TextboxErrorBubbleStyle" TargetType="{x:Type TextBox}" BasedOn="{StaticResource ResourceKey=TextBoxValidationStyle}">
        <Setter Property="Validation.ErrorTemplate">
            <Setter.Value>
                <ControlTemplate>
                    <DockPanel LastChildFill="true">
    
                        <Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="10" Height="10" CornerRadius="10"
                            ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
    
                            <TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white"/>
                        </Border>
    
                        <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
                            <Border BorderBrush="red" BorderThickness="1" />
                        </AdornedElementPlaceholder>
    
                    </DockPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

  2. Использование с контролем.

    <TextBox Text="{Binding Path=FirstName, Mode=TwoWay, ValidatesOnDataErrors=True,NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}"
                Style="{StaticResource TextBoxValidationStyle}" Width="100" Margin="3 5 3 5"/>
     <TextBox Text="{Binding Path=LastName, Mode=TwoWay, ValidatesOnDataErrors=True,NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}"
                Style="{StaticResource TextboxErrorBubbleStyle}" Width="100" Margin="0 5 3 5"/>
    

  3. Образец модели класса.

    класс Заказчик: INotifyPropertyChanged, IDataErrorInfo { приватная строка firstName; приватная строка lastName;

    public string FirstName
    {
        get { return firstName; }
        set
        {
            if (firstName != value)
            {
                firstName = value;
                RaisePropertyChanged("FirstName");
            }
        }
    }
    
    public string LastName
    {
        get { return lastName; }
        set
        {
            if (lastName != value)
            {
                lastName = value;
                RaisePropertyChanged("LastName");
            }
        }
    }
    public string Error
    {
        get { throw new System.NotImplementedException(); }
    }
    
    public string this[string columnName]
    {
        get
        {
            string message = null;
            if (columnName == "FirstName" && string.IsNullOrEmpty(FirstName))
            {
                message = "Please enter FirstName";
            }
            if (columnName == "LastName" && string.IsNullOrEmpty(LastName))
            {
                message = "Please enter LastName";
            }
            return message;
        }
    }
    

    }

  4. Пользовательский интерфейс. Смотри и чувствуй.

enter image description here

0 голосов
/ 14 июля 2009

Из того, что я предполагаю, Validation.ErrorTemplate = "{x: Null}" удаляет красный прямоугольник, когда присутствует ошибка. Это может быть установлено, чтобы не иметь красный прямоугольник вокруг текстового поля при запуске формы.

Для ошибки, показанной в форме, я видел где-то в коде: Content="{Binding ElementName=lastNameTxt, Path=(Validation.Errors).CurrentItem}", так что я все еще догадываюсь, что это Привязка к текстовому полю (не к модели данных), и проверьте, есть ли ошибка со статической проверкой . Ошибки, которые могут подключиться к IDataErroInfo из модели данных?

Правильно ли я угадал?

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