似乎有些人在 Silverlight 中更新文本 AutoCompleteBox 时遇到问题,遗憾的是我已经加入了这个行列。
我有一个像这样的名为 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://stackoverflow.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 中的新值时。字段更新,性别设置,一切看起来都很好。单击撤消成功地将字段更改回其原始值 - 一切看起来都很花哨。
但是,当用户尝试重做更改时,屏幕上的值不会更新。基础值已更改,Gender 属性上的 get 被调用,并且 Model.Gender 值已正确设置。但后来什么都没有。画面不更新。可编辑组合控件 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" />
当通过键盘输入新值时,我的撤消/重做实现适用于不可编辑组合控件和可编辑组合控件。重做问题仅在通过下拉切换按钮更改属性时才明显。我知道基础值已按照前面的说明正确更新(例如,当 ValidatesOnDataErrors 处于打开状态时,当我重做并将 Gender 属性设置回有效值时,表示错误的红色边框消失 - 但是,文本保持不变)。
无论出于何种原因,TextBoxChanged 事件在上述情况下都不会触发。会不会是事件正在其他地方处理?