Принудительное обновление представления об ошибке проверки с использованием шаблона MVVM - PullRequest
2 голосов
/ 18 июля 2010

У меня проблема: У меня есть некоторые элементы управления в форме (флажок, поле со списком, слайдер, текстовое поле). Их значения связаны с различными свойствами модели представления.
Когда свойство модели представления имеет определенное значение, я хотите, чтобы эти элементы управления были «фиксированными» (отображается сообщение об ошибке, и они устанавливаются на некоторое фиксированное значение (например: флажок снят, когда пользователь пытается его установить, ползунок установлен на определенное значение, выбранный элемент комбо является вторым элементом в списке). Я сделал это так (упрощенный пример для текстового поля): По мнению:

            <TextBox 
                Text="{Binding ViewModelProperty, 
                               NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged, 
                               ValidatesOnDataErrors=True, NotifyOnValidationError=True}"
                />

В представлении модель: Свойство определяется так:

String _ViewModelProperty;
public String ViewModelProperty
{
    get
    {
        return _ViewModelProperty;
    }
    set
    {

        _ViewModelProperty = value;
        OnPropertyChanged("ViewModelProperty");
    }
}

и реализация IDataErrorInfo:

String IDataErrorInfo.this[String propertyName]
{
    get
    {
        String error = null;
        if (propertyName == "ViewModelProperty")
        {
            if (ViewModelProperty != "FixedValue")
            {
                error = DisplayMessage("You can only set a fixed value here");
                ViewModelProperty= "FixedValue";
            }
        }
        return error;
    }
}

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

Я не могу понять, как принудительно обновить значение элемента управления.

Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 19 июля 2010

Способ принудительного повторного связывания заключается в вызове BindingExpression.UpdateTarget() или BindingExpression.UpdateSource(), в зависимости от ситуации.

Конечно, вы не хотите этого в своей модели представления.

Поскольку я внедряю модели видов в свои виды и устанавливаю их как DataContext в конструкторе видов, я бы сделал что-то вроде следующего:

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

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

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

0 голосов
/ 19 июля 2010

Я не использую свойство IsEnabled, потому что это требования: ничего не отключено, отображается только сообщение, если установлены «недопустимые» значения.
Другое требование - не вводить модели представления в представление ... Мыиметь некоторые классы «рабочей области», которые связывают представление с моделью представления, поэтому ни одно представление не знает о прикрепленном к нему экземпляре модели представления.Конечно, инъекция может быть сделана из рабочей области ... Я попробовал это, но все равно не работает.
Но разве нет другого элегантного и MVVM-иш-метода?Я подготовил очень простой пример, иллюстрирующий мою проблему.
У меня есть 2 текстовых поля, привязанных к одному и тому же свойству в модели представления:

<StackPanel>
    <Label>First text box</Label>
    <TextBox 
        Text="{Binding Path=Property,
                 NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged, 
                 ValidatesOnDataErrors=True, NotifyOnValidationError=True}"
    />
    <Label>Second text box</Label>
    <TextBox
        Text="{Binding Path=Property, 
                 NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged, 
                 ValidatesOnDataErrors=True, NotifyOnValidationError=True}"
        />
</StackPanel>

Модель представления имеет реализацию IDataErrorInfo:

public String this[String propertyName]
{
    get 
    {
        String error = null;
        if (propertyName == "Property")
        {
            if (Property != "1000")
            {
                error ="Only value '1000' is accepted here.";
                MessageBox.Show(error, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                Property = "1000";
            }
        }
        return error;

    }
}

Первоначально значение равно «1000».
Если я добавлю «0» в одно текстовое поле, появится сообщение, другое текстовое поле будет корректно обновлено до «1000»,но значение выделенного текстового поля остается «10000».
Мне кажется, что я здесь упускаю что-то важное.

Люсия

0 голосов
/ 19 июля 2010

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

<Slider IsEnabled={Binding CanUserChangeSlider} ... />

Так в установщике для связанного свойства Comboboxes:

set 
{
  // store value in backing store
  // RaisePropertyChanged

  if (value == true)
  {
    this.CanUserChangeSlider = false;
    // the bound property for slider set to certain value
    // the bound property for combobox changed to be a certain value
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...