有没有一种方法可以捕获尝试更改WPF TreeView中当前选定项的操作,并可能取消它?
树视图中的元素表示具有某些属性的页面。我想问用户是否要放弃在页面上进行的更改,保存更改或保留在当前页面。
为了得到一个更简单的解决方案。重写PreviewMouseDown事件,您将获得所需的结果。
private void Tree_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
// first did the user click on a tree node?
var source = e.OriginalSource as DependencyObject;
while (source != null && !(source is TreeViewItem))
source = VisualTreeHelper.GetParent(source);
source = source as TreeViewItem;
if (source == null) return;
var treeView = sender as TreeView;
if (treeView == null) return;
// validate our current item to decide if we allow the change
// or do whatever checks you wish
if (!ItemIsValid(treeView.SelectedItem))
{
// it's not valid, so cancel the attempt to select an item.
e.Handled = true;
}
// Maybe you want to check the about to be selected value?
MyClass data = source.DataContext;
if (!CanSelect(data))
{
// we can't select this, so cancel the attempt to select.
e.Handled = true;
}
}
我想你可能不会喜欢这个答案……WPF TreeView
不太友好。首先,最重要的是……
捕获更改所选项的尝试:
最简单的方法是处理 SelectedItemChanged
事件:
private void TreeView_SelectedItemChanged(object sender,
RoutedPropertyChangedEventArgs<object> e)
{
e.Handled = true;
}
Attached Property
内处理它。更加复杂的是,如果你要创建一个Attached Property
来处理SelectedItemChanged
事件,那么你可能也会实现一个SelectedItem
Attached Property
,可以在Two-Way Mode
中绑定。我不会在这里详细介绍如何做到这一点,因为有很多在线教程可供参考。
...并且可能会取消它:
如果你有一个SelectedItem
Attached Property
,那么你可以监视该属性的变化。当然,有个问题...视图模型接收到变化时,UI已经发生了改变。因此,虽然你可以阻止数据在视图模型中发生变化,但无法阻止在UI上进行选择。
不过这并不是个大问题,因为通过Two-Way Binding
,你将能够在必要时将UI选择设置回前一个项目...看看这个伪代码:
public YourDataType SelectedItem
{
get { return selectedItem; }
set
{
if (selectedItem != value)
{
if (selectedItem.HasChanges)
{
if (WindowManager.UserAcceptsLoss())
{
selectedItem = value;
NotifyPropertyChanged("SelectedItem");
}
else ResetSelectedItem(selectedItem);
}
else
{
selectedItem = value;
NotifyPropertyChanged("SelectedItem");
}
}
}
}
为了满足您的需求,您还有很多工作要做……祝你好运。
使用PreviewMouseDown
只是半个解决方案。用户可能会通过键盘更改选择。在所有树形项中使用TreeViewItem.Selected
:
private TreeViewItem _currenеTreeViewItem;
private bool _treeViewItemSelectedWork;
private void TreeViewItem_Selected(object sender, RoutedEventArgs e)
{
if(_treeViewItemSelectedWork)
return;
_treeViewItemSelectedWork = true;
TreeViewItem newTreeViewItem = (TreeViewItem) sender;
if (newTreeViewItem.IsSelected)
{
if (_currenеTreeViewItem == null)
_currenеTreeViewItem = newTreeViewItem;
if (!Equals(newTreeViewItem, _currenеTreeViewItem))
{
if (MessageBox.Show("Undo into previous selection?", "Undo", MessageBoxButton.YesNo,
MessageBoxImage.None) == MessageBoxResult.Yes)
{
newTreeViewItem.IsSelected = false;
_currenеTreeViewItem.IsSelected = true;
}
else
{
_currenеTreeViewItem.IsSelected = false;
_currenеTreeViewItem = newTreeViewItem;
_currenеTreeViewItem.IsSelected = true;
}
}
}
_treeViewItemSelectedWork = false;
}