WPF,TreeView选择更改

6

有没有一种方法可以捕获尝试更改WPF TreeView中当前选定项的操作,并可能取消它?

树视图中的元素表示具有某些属性的页面。我想问用户是否要放弃在页面上进行的更改,保存更改或保留在当前页面。


有没有可能通过处理 PreviewMouseDown(e.Handled=true)来实现这一点。 - Ravuthasamy
3个回答

7

为了得到一个更简单的解决方案。重写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;
        }
    }

这应该是被接受的答案。简单明了,完美地解决了问题。 - Jim Gomes
3
如果你想使用鼠标以外的其他工具进行选择,这种方法就无法奏效。 - Mikkel K.

4

我想你可能不会喜欢这个答案……WPF TreeView 不太友好。首先,最重要的是……

捕获更改所选项的尝试:

最简单的方法是处理 SelectedItemChanged 事件:

private void TreeView_SelectedItemChanged(object sender, 
RoutedPropertyChangedEventArgs<object> e)
{
    e.Handled = true;
}

很遗憾,如果你使用MVVM的话,就需要在Attached Property内处理它。更加复杂的是,如果你要创建一个Attached Property来处理SelectedItemChanged事件,那么你可能也会实现一个SelectedItemAttached Property,可以在Two-Way Mode中绑定。我不会在这里详细介绍如何做到这一点,因为有很多在线教程可供参考。

...并且可能会取消它

如果你有一个SelectedItemAttached 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");
            }
        }
    }
}

为了满足您的需求,您还有很多工作要做……祝你好运。


0

使用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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接