[英]How to cancel a ComboBox SelectionChanged event?
Is there an easy method to prompt the user to confirm a combo box selection change and not process the change if the user selected no? 是否有一种简单的方法来提示用户确认组合框选择更改,如果用户选择“否”,则不处理更改?
We have a combo box where changing the selection will cause loss of data. 我们有一个组合框,更改选择将导致数据丢失。 Basically the user selects a type, then they are able to enter attributes of that type.
基本上用户选择一种类型,然后他们就能输入该类型的属性。 If they change the type we clear all of the attributes as they may no longer apply.
如果他们更改了类型,我们会清除所有属性,因为它们可能不再适用。 The problem is that to under the selection you raise the
SelectionChanged
event again. 问题是,在选择下,您再次引发
SelectionChanged
事件。
Here is a snippet: 这是一个片段:
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;
}
}
I have two solutions, neither of which I like. 我有两个解决方案,我都不喜欢。
After the user selects 'No' , remove the SelectionChanged
event handler, change the selected item and then register the SelectionChanged
event handler again. 用户选择“否”后 ,删除
SelectionChanged
事件处理程序,更改所选项目,然后再次注册SelectionChanged
事件处理程序。 This means you have to hold onto a reference of the event handler in the class so that you can add and remove it. 这意味着您必须在类中保留事件处理程序的引用,以便您可以添加和删除它。
Create a ProcessSelectionChanged
boolean as part of the class. 创建
ProcessSelectionChanged
布尔值作为类的一部分。 Always check it at the start of the event handler. 始终在事件处理程序的开头检查它。 Set it to false before we change the selection back and then reset it to true afterwards.
在我们更改选择之前将其设置为false,然后将其重置为true。 This will work, but I don't like using flags to basically nullify an event handler.
这将工作,但我不喜欢使用标志基本上使事件处理程序无效。
Anyone have an alternative solution or an improvement on the ones I mention? 任何人都有替代解决方案或改进我提到的?
I found this good implementation. 我发现这个很好的实现。
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;
}
source: http://www.amazedsaint.com/2008/06/wpf-combo-box-cancelling-selection.html 来源: http : //www.amazedsaint.com/2008/06/wpf-combo-box-cancelling-selection.html
I remember needing to do this a while back. 我记得有一段时间需要这样做。 It took me about a week of research and attempts before I found a good solution.
在我找到一个好的解决方案之前,我花了大约一周的研究和尝试。 I posted it here:
我在这里发布了:
WPF: Cancel a user selection in a databound ListBox? WPF:取消数据绑定列表框中的用户选择?
FYI, it's an MV-VM based solution (if you aren't using the MV-VM pattern, you should be!) 仅供参考,这是一个基于MV-VM的解决方案(如果你没有使用MV-VM模式,你应该是!)
也许创建一个派生自ComboBox
的类,并重写OnSelectedItemChanged
(或OnSelectionChangeCommitted
。)
Validating within the SelectionChanged
event handler allows you to cancel your logic if the selection is invalid, but I don't know of an easy way to cancel the event or item selection. 如果选择无效,则在
SelectionChanged
事件处理程序内进行验证允许您取消逻辑,但我不知道取消事件或项目选择的简单方法。
My solution was to sub-class the WPF combo-box and add an internal handler for the SelectionChanged
event. 我的解决方案是对WPF组合框进行子类化,并为
SelectionChanged
事件添加内部处理程序。 Whenever the event fires, my private internal handler raises a custom SelectionChanging
event instead. 每当事件触发时,我的私有内部处理程序都会引发自定义
SelectionChanging
事件。
If the Cancel
property is set on the corresponding SelectionChangingEventArgs
, the event isn't raised and the SelectedIndex
is reverted to its previous value. 如果在相应的
SelectionChangingEventArgs
上设置了Cancel
属性,则不会引发该事件,并且SelectedIndex
将还原为其先前的值。 Otherwise a new SelectionChanged
is raised that shadows the base event. 否则会引发一个新的
SelectionChanged
,它会遮蔽基本事件。 Hopefully this helps! 希望这有帮助!
EventArgs and handler delegate for SelectionChanging event: SelectionChanging事件的EventArgs和handler委托:
public class SelectionChangingEventArgs : RoutedEventArgs
{
public bool Cancel { get; set; }
}
public delegate void
SelectionChangingEventHandler(Object sender, SelectionChangingEventArgs e);
ChangingComboBox class implementation: 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;
}
}
}
I do not believe using the dispatcher to post (or delay) a property update is a good solution, it is more of a workaround that is not really needed. 我不相信使用调度程序发布(或延迟)属性更新是一个很好的解决方案,它更像是一种并非真正需要的解决方法。 The following solution i fully mvvm and it does not require a dispatcher.
以下解决方案我完全mvvm,它不需要调度程序。
In the view code behind hook to the SelectionChanged event and update the Source (ie, the VM) or the Target (ie the V) in accordance to whether the VM.ConfirmChange(...) method returned value as follows: 在视图代码后面挂钩到SelectionChanged事件并根据VM.ConfirmChange(...)方法返回值更新Source(即VM)或Target(即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();
}
}
}
}
In WPF dynamically set the object with 在WPF中动态设置对象
if (sender.IsMouseCaptured)
{
//perform operation
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.