ユーザーにコンボボックスの選択の変更を確認し、ユーザーが「いいえ」を選択した場合は変更を処理しないように促す簡単な方法はありますか?
選択を変更するとデータが失われるコンボボックスがあります。基本的に、ユーザーはタイプを選択すると、そのタイプの属性を入力できます。それらがタイプを変更する場合、適用されなくなる可能性があるため、すべての属性をクリアします。問題は、選択の下でSelectionChanged
イベントを再度発生させることです。
これがスニペットです:
if (e.RemovedItems.Count > 0)
{
result = MessageBox.Show("Do you wish to continue?",
"Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.No)
{
if (e.RemovedItems.Count > 0)
((ComboBox)sender).SelectedItem = e.RemovedItems[0];
else
((ComboBox)sender).SelectedItem = null;
}
}
私には2つの解決策がありますが、どちらも好きではありません。
ユーザーが'No'を選択した後、SelectionChanged
イベントハンドラーを削除し、選択したアイテムを変更してから、SelectionChanged
イベントハンドラーを再登録します。つまり、クラスのイベントハンドラーの参照を保持して、追加および削除できるようにする必要があります。
クラスの一部としてProcessSelectionChanged
ブール値を作成します。イベントハンドラの開始時に必ず確認してください。選択を元に戻す前にfalseに設定し、後でtrueにリセットします。これは機能しますが、基本的にイベントハンドラーを無効にするためにフラグを使用するのは好きではありません。
誰かが私が言及したものの代替ソリューションまたは改善がありますか?
しばらく前にこれを行う必要があったことを覚えています。良い解決策が見つかるまでに、約1週間の調査と試行が必要でした。ここに投稿しました:
WPF:データバインドされたリストボックスでのユーザー選択をキャンセルしますか?
参考までに、これはM-V-VMベースのソリューションです(M-V-VMパターンを使用していない場合は、使用する必要があります)。
私はこの良い実装を見つけました。
private bool handleSelection=true;
private void ComboBox_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
if (handleSelection)
{
MessageBoxResult result = MessageBox.Show
("Continue change?", MessageBoxButton.YesNo);
if (result == MessageBoxResult.No)
{
ComboBox combo = (ComboBox)sender;
handleSelection = false;
combo.SelectedItem = e.RemovedItems[0];
return;
}
}
handleSelection = true;
}
ソース: http://www.amazedsaint.com/2008/06/wpf-combo-box-cancelling-selection.html
多分ComboBox
から派生したクラスを作成し、OnSelectedItemChanged
(またはOnSelectionChangeCommitted
。)をオーバーライドします。
WPFでは、オブジェクトを動的に設定します
if (sender.IsMouseCaptured)
{
//perform operation
}
SelectionChanged
イベントハンドラー内で検証すると、選択が無効な場合にロジックをキャンセルできますが、イベントまたはアイテムの選択をキャンセルする簡単な方法がわかりません。
私の解決策は、WPFコンボボックスをサブクラス化し、SelectionChanged
イベントの内部ハンドラーを追加することでした。イベントが発生するたびに、代わりに私のプライベート内部ハンドラーがカスタムSelectionChanging
イベントを発生させます。
Cancel
プロパティが対応するSelectionChangingEventArgs
に設定されている場合、イベントは発生せず、SelectedIndex
は以前の値に戻ります。それ以外の場合は、ベースイベントをシャドウする新しいSelectionChanged
が発生します。うまくいけば、これが役立ちます!
EventArgsおよびSelectionChangingイベントのハンドラーデリゲート:
public class SelectionChangingEventArgs : RoutedEventArgs
{
public bool Cancel { get; set; }
}
public delegate void
SelectionChangingEventHandler(Object sender, SelectionChangingEventArgs e);
ChangingComboBoxクラスの実装:
public class ChangingComboBox : ComboBox
{
private int _index;
private int _lastIndex;
private bool _suppress;
public event SelectionChangingEventHandler SelectionChanging;
public new event SelectionChangedEventHandler SelectionChanged;
public ChangingComboBox()
{
_index = -1;
_lastIndex = 0;
_suppress = false;
base.SelectionChanged += InternalSelectionChanged;
}
private void InternalSelectionChanged(Object s, SelectionChangedEventArgs e)
{
var args = new SelectionChangingEventArgs();
OnSelectionChanging(args);
if(args.Cancel)
{
return;
}
OnSelectionChanged(e);
}
public new void OnSelectionChanged(SelectionChangedEventArgs e)
{
if (_suppress) return;
// The selection has changed, so _index must be updated
_index = SelectedIndex;
if (SelectionChanged != null)
{
SelectionChanged(this, e);
}
}
public void OnSelectionChanging(SelectionChangingEventArgs e)
{
if (_suppress) return;
// Recall the last SelectedIndex before raising SelectionChanging
_lastIndex = (_index >= 0) ? _index : SelectedIndex;
if(SelectionChanging == null) return;
// Invoke user event handler and revert to last
// selected index if user cancels the change
SelectionChanging(this, e);
if (e.Cancel)
{
_suppress = true;
SelectedIndex = _lastIndex;
_suppress = false;
}
}
}
ディスパッチャーを使用してプロパティの更新を投稿(または遅延)することは良い解決策ではないと思います。これは、実際には必要のない回避策です。次のソリューションは完全にmvvmで、ディスパッチャーは必要ありません。
ビューのコードビハインドでSelectionChangedイベントにフックし、VM.ConfirmChange(...)メソッドが次のように値を返したかどうかに従って、ソース(つまり、VM)またはターゲット(つまり、V)を更新します。
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(e.AddedItems.Count != 0)
{
var selectedItem = e.AddedItems[0];
if (e.AddedItems[0] != _ViewModel.SelectedFormatType)
{
var comboBoxSelectedItemBinder = _TypesComboBox.GetBindingExpression(Selector.SelectedItemProperty); //_TypesComboBox is the name of the ComboBox control
if (_ViewModel.ConfirmChange(selectedItem))
{
// Update the VM.SelectedItem property if the user confirms the change.
comboBoxSelectedItemBinder.UpdateSource();
}
else
{
//otherwise update the view in accordance to the VM.SelectedItem property
comboBoxSelectedItemBinder.UpdateTarget();
}
}
}
}