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...
}
これにより、ユーザーはトグル ボタンをクリックし、ドロップダウン リストから選択してオプションを選択したり、標準のコンボ ボックス コントロールのように新しい値を入力したりできます。
私のビューには、Gender プロパティを含むビューモデルにバインドされた EditableCombo コントロールがあります。
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 値が正しく設定されます。しかし、その後何もありません。画面が更新されません。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" />
元に戻す/やり直しの私の実装は、編集不可能なコンボ コントロールと、新しい値がキーボードから入力されたときの編集可能なコンボに対して正常に機能します。やり直しの問題は、ドロップダウン トグル ボタンを介してプロパティが変更された場合にのみ明らかになります。前に説明したように、基礎となる値が正しく更新されていることを知っています (また、たとえば、ValidatesOnDataErrors がオンになっているため、Gender プロパティをやり直して有効な値に戻すと、エラーを示す赤い境界線が消えますが、テキストは変更されません。 )。
何らかの理由で、TextBoxChanged イベントは上記のシナリオでは発生しません。イベントが他の場所で処理されている可能性はありますか?