Silverlight AutoCompleteBox NotifyPropertyChanged не обновляет экран

Кажется, у некоторых людей возникают проблемы с обновлением текста AutoCompleteBox в Silverlight, и, к сожалению, я вступил в ряды.

У меня есть производный класс под названием EditableCombo, как это;

  public class EditableCombo : AutoCompleteBox
  {
    ToggleButton _toggle;
    Path _btnPath;
    TextBox _textBox;
    ...animation and toggle button stuff...

    public override void OnApplyTemplate()
    {
      ...animation and toggle button stuff...

      //required to overcome issue in AutoCompleteBox that prevents the text being updated in some instances
      //http://stackru.com/questions/8488968/silverlight-5-autocompletebox-bug?rq=1
      _textBox = GetTemplateChild("Text") as TextBox;

      if (_textBox == null)
        throw new NullReferenceException();

      if (_textBox != null)
        _textBox.TextChanged += TextBoxChanged;

      base.OnApplyTemplate();      
    }

    void TextBoxChanged(object sender, TextChangedEventArgs e)
    {
      Debug.WriteLine("text box changed fired new value: " + _textBox.Text);
      Text = _textBox.Text;
      OnTextChanged(new RoutedEventArgs());      
    }

    ...animation and toggle button stuff...
  }

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

Мое представление имеет элемент управления EditableCombo, связанный с моделью представления, содержащей свойство Gender;

public string Gender
{
  get
  {
    Debug.WriteLine("Gender get executed - Model.Gender = " + Model.Gender);
    return Model.Gender;
  }
  set
  {        
    if (Model.Gender == value) return;        
    MonitoredNotificationObject.RaisePropertyChanged(() => Model.Gender, value, this, true);        
  }
}

Моя модель представления использует объект MonitoredNotificationObject для ведения истории отмен / повторов и уведомления о любых изменениях свойств;

    public void RaisePropertyChanged(Expression<Func<string>> propertyExpression,
                                     string newValue,
                                     object sender,
                                     bool canChain)
    {
      PropertyExpressionHelper propertyExpressionHelper = new PropertyExpressionHelper(propertyExpression)
                                       {
                                         NewValue = newValue
                                       };

#if DEBUG
      VerifyPropertyExists(propertyExpressionHelper.Name, sender);
#endif

      var monitoredAction = new MonitoredProperty<TViewModel, TModel>(this)
                              {
                                ObjectPropertyName = propertyExpressionHelper.MakeObjectPropertyName(),
                                PropertyExpressionHelper = propertyExpressionHelper,
                                Sender = (TViewModel) sender,
                                CanChain = canChain
                              };

      propertyExpressionHelper.SetToNewValue();
      RaisePropertyChanged(propertyExpressionHelper.Name, sender);
      MaintainMonitorState(monitoredAction);
    }

Отмена и повтор реализованы, как показано ниже (отмена показана);

public override bool UndoExecute(MonitoredObject<TViewModel, TModel> undoAction,
                                 Stack<MonitoredObject<TViewModel, TModel>> redoActions,
                                 Stack<MonitoredObject<TViewModel, TModel>> undoActions)
{
  PropertyExpressionHelper.SetToNewValue();
  redoActions.Push(undoAction);

  var action = (MonitoredProperty<TViewModel, TModel>) undoAction;
  HandleAutoInvokedProperties(action);

  if (action.CanChain)
  {
    if (undoActions.Any())
    {          
      if (CanDoChain(undoActions, action))
        return true;
    }
  }

  action.RaiseChange();
  Sender.RaiseCanExecuteChanges();
  return false;
}

Уведомление об изменении свойства создается следующим образом;

protected virtual void RaiseChange()
{
  MonitoredNotificationObject.RaisePropertyChanged(PropertyExpressionHelper.Name, Sender);

  if (RaiseChangeAction != null)
    RaiseChangeAction.Invoke();
}

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

Проблема заключается в том, что пользователь выбирает новое значение в EditableCombo из раскрывающегося списка. Поле обновляется, пол установлен и все выглядит нормально. Нажатие кнопки "Отменить" успешно изменяет поле на его первоначальное значение - все выглядит просто замечательно.

Однако, когда пользователь пытается повторить изменение, значение на экране не обновляется. Базовое значение изменяется, вызывается свойство get для Gender и правильно устанавливается значение Model.Gender. Но тогда ничего. Экран не обновляется. Элемент управления editablecombo TextBoxChangedEvent не срабатывает, поэтому неудивительно, что значение на экране неверно.

В основном элемент управления не уведомляется об изменении.

Есть идеи?

Обновить:

Представление, содержащее EditableCombo, имеет модель представления, содержащую свойство Gender. Свойство связано вот так;

<EditCombo:EditableCombo ItemsSource="{Binding Genders}"
    ItemTemplate="{StaticResource editableComboDataTemplate}"
    Style="{StaticResource EditableComboStyle}"
    Text="{Binding Path=Gender,
                  UpdateSourceTrigger=PropertyChanged,
                  Mode=TwoWay,
                  ValidatesOnDataErrors=True}"
    TextBoxStyle="{StaticResource editableComboDataEntryField}"
    ValueMemberPath="Value" />

Моя реализация undo / redo отлично работает для нередактируемых элементов управления combo и для editablecombo, когда новые значения вводятся через клавиатуру. Проблема возврата повторяется только тогда, когда свойство было изменено с помощью кнопки-переключателя. Я знаю, что базовые значения корректно обновляются, как объяснено ранее (а также, например, когда ValidatesOnDataErrors включен, когда я повторяю и устанавливаю свойство Gender обратно в допустимое значение, красная граница, означающая ошибку, исчезает - НО, текст остается неизменным).

По какой-то причине событие TextBoxChanged никогда не срабатывает в приведенном выше сценарии. Может ли событие быть обработано в другом месте?

1 ответ

Это работает, если вы добавите эту строку:

Model.Gender = value;

к установщику имущества?

Другие вопросы по тегам