Ahmad_kelany Ответов: 1

Wpf MVVM, как отключить команду на основе ошибки при сбое преобразования с помощью iNotifydataerrorinfo через viewmodel?


Всем привет,

У меня есть класс ValidatableBindableBase, который реализует интерфейс INotifyDataErrorInfo и интерфейс INotifyPropertyChanged.

Проверки, зависящие от аннотаций данных и пользовательских проверок, работают нормально.

Проблема заключается в том, что когда текстовое поле не преобразует входные данные в тип данных связанного свойства, отображается сообщение об ошибке "не удалось преобразовать из строки 'ab' в целое число", но ошибки viewmodel не обновляются с этой ошибкой, и поэтому команда, которая должна быть отключена при ошибке, не отключается..


Моя главная цель-отключить команду при возникновении ошибки преобразования, и я хочу сделать это из viewmodel, если это возможно

Команда can-execute (которая определяет, включена кнопка или нет), этот метод зависит от коллекции ошибок модели представления,
когда возникает исключение преобразования (например, когда вы вводите текст в текстовое поле, привязанное к deciaml), коллекция ошибок не затрагивается (поскольку установщик свойств никогда не вызывается), и, следовательно, can execute команды не возвращает false..

код:

Public Class BindableBase
    Implements INotifyPropertyChanged
    Protected Overridable Sub SetProperty(Of T)(ByRef member As T,
                                                ByVal val As T,
                                                <CallerMemberName> Optional propertyName As String = Nothing)

        If Object.Equals(member, val) Then Return
        member = val
        RaisePropertyChanged(propertyName)
    End Sub
    Sub RaisePropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
End Class




Public Class ValidatableBindableBase
    Inherits BindableBase
    Implements INotifyDataErrorInfo
    Private _errors As New Dictionary(Of String, List(Of String))

    Public ReadOnly Property HasErrors As Boolean Implements INotifyDataErrorInfo.HasErrors
        Get
            Return _errors.Count > 0
        End Get
    End Property

    Public Event ErrorsChanged As EventHandler(Of DataErrorsChangedEventArgs) Implements INotifyDataErrorInfo.ErrorsChanged

    Public Function GetErrors(propertyName As String) As IEnumerable Implements INotifyDataErrorInfo.GetErrors
        If propertyName Is Nothing Then Return Nothing
        If _errors.ContainsKey(propertyName) Then
            Return _errors(propertyName)
        Else
            Return Nothing
        End If
    End Function

    Protected Overrides Sub SetProperty(Of T)(ByRef member As T, val As T, <CallerMemberName> Optional propertyName As String = Nothing)
        MyBase.SetProperty(member, val, propertyName)
        ClearErrors(propertyName)
        ValidateDataAnnotationsForProperty(propertyName, val)
        ValidateCustomErrors(propertyName)
    End Sub

    Private Sub ValidateDataAnnotationsForProperty(Of T)(ByVal propertyName As String, ByVal value As T)
        Dim results As New List(Of ValidationResult)
        Dim context As New ValidationContext(Me)
        context.MemberName = propertyName
        Validator.TryValidateProperty(value, context, results)
        If results.Any() Then
            _errors(propertyName) = results.Select(Function(r) r.ErrorMessage).ToList()
        Else
            _errors.Remove(propertyName)
        End If
        RaiseErrorsChanged(propertyName)
    End Sub
    Sub RaiseErrorsChanged(ByVal propertyName As String)
        RaiseEvent ErrorsChanged(Me, New DataErrorsChangedEventArgs(propertyName))
    End Sub

    Private Sub ValidateCustomErrors(ByVal propertyName As String)
        Dim errors = ValidateProperty(propertyName)
        If errors IsNot Nothing Then
            For Each e In errors
                AddError(propertyName, e)
            Next
        End If
    End Sub
    Protected Sub AddError(ByVal propertyName As String, ByVal err As String)
        If Not _errors.ContainsKey(propertyName) Then _errors(propertyName) = New List(Of String)
        If Not _errors(propertyName).Contains(err) Then
            _errors(propertyName).Add(err)
            RaiseErrorsChanged(propertyName)
        End If
    End Sub
    Protected Sub ClearErrors(ByVal propertyName As String)
        If _errors.ContainsKey(propertyName) Then
            _errors.Remove(propertyName)
            RaiseErrorsChanged(propertyName)
        End If
    End Sub
    Protected Overridable Function ValidateProperty(ByVal propertyName As String) As IEnumerable(Of String)
        Return Nothing
    End Function
End Class



и это свойство из ViewModel характерными validatableBindableBase:

Private _price As Decimal
<Required(ErrorMessage:="سعر الصنف لا يمكن أن يكون فارغا")>
<Range(0.0, Double.MaxValue, ErrorMessage:="سعر الصنف لا يمكن أن يكون سالبا")>
Public Property Price As Decimal
    Get
        Return _price
    End Get
    Set(value As Decimal)
        SetProperty(_price, value)
    End Set
End Property


Что я уже пробовал:

Здесь есть предлагаемое решение:
Проверки в WPF[^]

но он использует логику проверки в представлении, мне нужно сделать всю проверку в viewmodel, если это возможно.

а также, когда я попробовал это сделать, он изменил только сообщение, показанное под текстовым полем (я использую шаблон ошибки), но также не сделал команду, которая должна быть отключена при отключении ошибки..

1 Ответов

Рейтинг:
1

#realJSOP

Вы не отключаете команды - вы отключаете элементы управления, которые их вызывают.

Представление должно быть в состоянии обнаружить состояние ошибки и отключить элемент управления на основе этого состояния.

Вот как это должно работать.


Richard Deeming

Это не путь WPF. Кнопки/меню/и т. д. привязаны к командам, и команда определяет, может ли она выполняться. Элемент управления включается или отключается в зависимости от команды, а не наоборот.

Обзор Командования | Microsoft Docs[^]

Ahmad_kelany

Да,я знаю об этом.,
Может быть, я не очень хорошо прояснил свою проблему, но я имею в виду, что команда может выполняться, которая определяет, включена ли кнопка или нет, этот метод зависит от коллекции ошибок модели представления,
когда возникает исключение преобразования (например, когда вы вводите текст в текстовое поле, привязанное к deciaml), коллекция ошибок не затрагивается (поскольку установщик свойств никогда не вызывается), и, следовательно, can execute команды не возвращает false..