Как получить недопустимые значения в представлении WPF - PullRequest
0 голосов
/ 18 сентября 2018

Если у меня есть представление WPF с текстовым полем, имеющим привязку к десятичному (или любому другому числовому формату), я автоматически получаю визуальную подсказку, если я ввожу букву или любой другой недопустимый символ, и значение не передается вviewmodel (точка останова на установщике никогда не достигается).Если я ввожу номер, все работает нормально.Чтобы отключить мою кнопку сохранения (ICommand), я хотел бы получить информацию в моей модели представления о том, что в представлении есть ошибка в стиле MVVM.Подсказки, где это поведение задокументировано, приветствуются!

Таким образом, целевая ситуация выглядит следующим образом:

current situation as is by WPF standard

то, что я хочу, это отключение «сохранить и закрыть»: enter image description here

XAML:

    <TextBox Text="{Binding Path=SelectedItem.Punkte_Seite_max, UpdateSourceTrigger=PropertyChanged}"/>

ViewModel

  public int Punkte_Seite_max
{
  get { return _punkte_Seite_max; }
  set
  {
    _punkte_Seite_max = value;
    Changed(); //INotifyPropertyChanged  call
  }
}

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

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

Ошибка, показанная выше, создается в представлении, потому что в WPF нет конвертера из букв в int (каким он должен быть).Чтобы поднять эту проблему, привязка должна иметь NotifyOnValidationError = True .

 <TextBox Text="{Binding Path=SelectedItem.Punkte_Seite_max, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True}"

Это вызывает всплеск Validation.Error событие, которое может быть захвачено в любом месте дерева.Я решил захватить его с помощью перенаправленного триггера событий, например: XAML:

<Window
...
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" >
    <i:Interaction.Triggers>
    <userInterface:RoutedEventTrigger RoutedEvent="{x:Static Validation.ErrorEvent}" >
        <userInterface:ViewErrorCounterAction ViewErrorCounter="{Binding Path=ViewValidationErrorCount, Mode=TwoWay}"/>
    </userInterface:RoutedEventTrigger>
</i:Interaction.Triggers>

Таким образом, привязка к twoway - это MVVM-okayish ссылка на мою модель представления.

ViewErrorCounterAction основан на этот ответ SO :

public class ViewErrorCounterAction : TriggerAction<DependencyObject> {
public ViewErrorCounterAction()
{
    ViewErrorCounter = 0;  // initalize with 0 as there should not be such errors when the window is loaded
}

public int ViewErrorCounter
{
    get
    {
        return System.Convert.ToInt32(GetValue(ViewErrorCounterProperty));
    }
    set
    {
        SetValue(ViewErrorCounterProperty, value);
    }
}

public static readonly DependencyProperty ViewErrorCounterProperty = DependencyProperty.Register("ViewErrorCounter", typeof(int), typeof(ViewErrorCounterAction), new PropertyMetadata(null));

protected override void Invoke(object parameter)
{
    var e = (ValidationErrorEventArgs)parameter;
    if ((e.Action == ValidationErrorEventAction.Added))
        ViewErrorCounter = ViewErrorCounter + 1;
    else if ((e.Action == ValidationErrorEventAction.Removed))
        ViewErrorCounter = ViewErrorCounter - 1;
}
}

Окончательно перенаправленный триггер события основан на https://sergecalderara.wordpress.com/2012/08/23/how-to-attached-an-mvvm-eventtocommand-to-an-attached-event/

Надеюсь, это поможет, и яБуду признателен за комментарии о том, как лучше решить эту проблему, если есть более элегантные способы:)

0 голосов
/ 18 сентября 2018

То, что вы хотите использовать, это INotifyDataErrorInfo найденная документация здесь .Это позволяет вам предоставлять пользовательскую проверку свойств, которые вы привязали к ViewModel.

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

ViewModel

public class ViewModel : INotifyDataErrorInfo
{
    // A place to store all error messages for all properties.
    private IDictionary<string, List<string>> propertyErrors = new Dictionary<string, List<string>>();

    public string Preis
    {
        get { return _preis; }
        set
        {
            // Only update if the value has actually changed.
            if (!string.Equals(_preis, value, StringComparison.Ordinal))
            {
                _preis = value;
                Changed();

                this.Validate();
            }
        }
    }

    // The event to raise when the error state changes.
    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;     

    // A method of getting all errors for the given known property.
    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
        if (propertyName != null)
        {
            if (propertyErrors.TryGetValue(propertyName, out var errors))
            {
                return errors;
            }
        }

        return null;
    }

    // Whether there are any errors on the ViewModel
    public bool HasErrors
    {
        get
        {    
            return propertyErrors.Values.Any(r =>r.Any());
        }
    }

    private void Validate()
    {
        // 1. HERE YOU CAN CHECK WHETHER Preis IS VALID AND ANY OTHER PROPERTIES
        // 2. Update the 'propertyErrors' dictionary with the errors
        // 3. Raise the ErrorsChanged event.
    }
}

XAML

Вы будетенужно изменить свой XAML на что-то вроде этого:

<TextBox>
    <Binding Path="Preis" UpdateSourceTrigger="PropertyChanged" ValidatesOnNotifyDataErrors="True"/>
</TextBox>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...