我对WPF有一个相当有趣的问题。我有一个树视图,到目前为止选择项目工作正常。问题是,当用户在树视图的空白区域内单击时,我想取消选择当前选定的项目。默认情况下,树视图保持选中当前项目,并且我添加了一个上下文菜单选项以取消选择它,这是相当硬的:
// Note: This is done recursivly from the start, so it
// works for child items as well
treeView.ItemContainerGenerator.ContainerFromItem(treeView.SelectedItem) as TreeViewItem).IsSelected = false;
此外,这是违反直觉的,因为它要求用户先进行右键单击,然后在用这种方式取消选择后,用户不能再通过单击该项目来选择它。这应该如何运作?
编辑:更多信息:我已经为TreeView
添加了处理程序以处理鼠标单击事件,但发件人始终是TreeView
实例,即使我直接点击TreeViewItem
1}}。如果我向我的TreeView.ItemTemplate
添加一个处理程序(即模板中的第一个子项),当我点击空白区域时(相当合乎逻辑),我从未得到过事件。代码如下所示:
private void MyTreeView_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if ((sender as TreeViewItem) == null)
{
// Always triggered
System.Diagnostics.Trace.Write("Empty area clicked");
}
}
XAML就是:
<TreeView x:Name="MyTreeView" Margin="3" MouseUp="MyTreeView_MouseUp">
答案 0 :(得分:6)
我发现这对我来说效果更好。我查看原始资源,如果它来自treeviewitem,它将是一个图像或文本块。我还使用带有HierarchicalDataTemplate的视图对象,而BasicTreeViewBase是我所有不同对象的基类。这是代码。
private void TemplateTreeView_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Right && !(e.OriginalSource is Image) && !(e.OriginalSource is TextBlock))
{
BasicTreeViewBase item = TemplateTreeView.SelectedItem as BasicTreeViewBase;
if (item != null)
{
TemplateTreeView.Focus();
item.IsSelected = false;
}
}
}
答案 1 :(得分:5)
在设置TreeViewItem.IsSelected后,可以通过调用FocusView在TreeView上解决不可选择的问题。
答案 2 :(得分:4)
还有两个问题:
由于这个原因,我使用了这个功能,但选择不得触发任何事件。
private void UnselectTreeViewItem(TreeView pTreeView)
{
if(pTreeView.SelectedItem == null)
return;
if(pTreeView.SelectedItem is TreeViewItem)
{
(pTreeView.SelectedItem as TreeViewItem).IsSelected = false;
}
else
{
TreeViewItem item = pTreeView.ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem;
if (item != null)
{
item.IsSelected = true;
item.IsSelected = false;
}
}
}
答案 3 :(得分:2)
我实施了一次通用选择控制,并且需要这种行为。
这是我的方法看起来(适用于树视图):
protected override void OnMouseUp(MouseButtonEventArgs e)
{
base.OnMouseUp(e);
DependencyObject dpSource = e.OriginalSource as DependencyObject;
if (dpSource.FindVisualAncestor(o => typeof(TreeViewItem).IsAssignableFrom(o.GetType())) == null)
UnselectAll();
}
基本上,从源头向上走树。如果找不到TreeViewItem,则用户单击空白区域。
答案 4 :(得分:2)
使用下面的扩展类
public static class TreeViewExtensions
{
public static TreeViewItem ContainerFromItem(this TreeView treeView, object item)
{
TreeViewItem containerThatMightContainItem = (TreeViewItem)treeView.ItemContainerGenerator.ContainerFromItem(item);
if (containerThatMightContainItem != null)
return containerThatMightContainItem;
else
return ContainerFromItem(treeView.ItemContainerGenerator, treeView.Items, item);
}
private static TreeViewItem ContainerFromItem(ItemContainerGenerator parentItemContainerGenerator, ItemCollection itemCollection, object item)
{
foreach (object curChildItem in itemCollection)
{
TreeViewItem parentContainer = (TreeViewItem)parentItemContainerGenerator.ContainerFromItem(curChildItem);
TreeViewItem containerThatMightContainItem = (TreeViewItem)parentContainer.ItemContainerGenerator.ContainerFromItem(item);
if (containerThatMightContainItem != null)
return containerThatMightContainItem;
TreeViewItem recursionResult = ContainerFromItem(parentContainer.ItemContainerGenerator, parentContainer.Items, item);
if (recursionResult != null)
return recursionResult;
}
return null;
}
}
然后在Treeview的MouseDown事件中使用扩展方法如下:
private void trview_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if ((sender as TreeViewItem) == null)
{
if (this.trview.ContainerFromItem(trview.SelectedItem) != null)
{
this.trview.ContainerFromItem(trview.SelectedItem).IsSelected = false;
}
}
this.trview.Focus();
}
希望它适合你。我让它以这种方式工作......
答案 5 :(得分:1)
在我找到一个对我有用的解决方案很久以后,我自己使用自定义的Tree List View实现了这种情况。
找到基本思想是捕获TreeViewItem.Selected
事件并将事件源保存到TreeView上的Tag
属性中。然后,当您需要清除它时,可以访问控件上的Tag
属性并将IsSelected
值设置为False。这适用于2级嵌套子级。希望它对你有用。
为了坚持:
TreeView声明
<TreeView Name="myTreeView" TreeViewItem.Selected="OnItemSelected"
ItemsSource="{Binding Source={StaticResource myHierarchicalData}}"/>
事件处理程序
private void OnItemSelected(object sender, RoutedEventArgs e)
{
myTreeView.Tag = e.OriginalSource;
}
清除选择逻辑
if (myTreeView.SelectedItem != null)
{
TreeViewItem selectedTVI = myTreeView.Tag as TreeViewItem;
// add your code here mine was selectedTVI.IsSelected = false;
}
答案 6 :(得分:0)
如果没有单击,则取消选择当前选择的TreeViewItem:
private void MyTreeView_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
if ((sender as TreeViewItem) == null) {
TreeViewItem item = MyTreeView.SelectedItem as TreeViewItem;
if(item != null){
item.IsSelected = false;
}
}
}
希望这就是你要找的东西!
答案 7 :(得分:0)
对于C#树视图,您使用treeview.SelectedNode = null;我不确定这是否适用于WPF。
答案 8 :(得分:0)
MVVM:在事件处理程序控件中/单击鼠标左键时调用此方法:
private void SetTreeViewSelection(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
var treeView = (TreeView)sender;
if (treeView.SelectedItem == null)
{
return;
}
IInputElement dropNode = treeView.InputHitTest(mouseButtonEventArgs.GetPosition(treeView));
if (dropNode is ScrollViewer)
{
var myBindableObject = (MyBindableObject)treeView.SelectedItem;
myBindableObject.IsSelected = false;
}
}