我尝试了这里讨论的解决方案:WPF treeview itemselected moves incorrectly when deleting an item
但是,在删除项目时,我仍然看到选择跳转到该父项。我做错了什么?
MainWindow.xaml
<Window x:Class="TreeViewDelete.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Tree View Delete sample" Height="350" Width="525">
<Window.Resources>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding Selected, Mode=TwoWay}"/>
<EventSetter Event="KeyDown" Handler="OnTreeKeyDown"/>
</Style>
<HierarchicalDataTemplate x:Key="recursiveTemplate" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<TreeView Name="m_tree" ItemsSource="{Binding Children}" ItemTemplate="{StaticResource recursiveTemplate}"/>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
private Container m_root, m_child;
public MainWindow()
{
InitializeComponent();
m_root = new Container("Root");
m_child = new Container("main");
m_child.Add(new Container("k1"));
m_child.Add(new Container("k2"));
m_child.Add(new Container("k3"));
m_child.Add(new Container("k4"));
m_child.Add(new Container("k5"));
m_root.Add(m_child);
m_tree.DataContext = m_root;
}
private IEnumerable<T> GetVisualAncestorsOfType<T>(DependencyObject obj) where T : DependencyObject
{
for (; obj != null; obj = VisualTreeHelper.GetParent(obj))
if (obj is T)
yield return (T)obj;
}
private void OnTreeKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Delete:
{
TreeViewItem item = sender as TreeViewItem;
if (item != null)
{
Container container = item.Header as Container;
if (container != null)
{
Container parent = container.Parent;
// Find the currently focused element in the TreeView's focus scope
DependencyObject focused =
FocusManager.GetFocusedElement(
FocusManager.GetFocusScope(m_tree)) as DependencyObject;
// Scan up the VisualTree to find the TreeViewItem for the parent
var parentContainer = (
from element in GetVisualAncestorsOfType<FrameworkElement>(focused)
where (element is TreeViewItem && element.DataContext == parent)
|| element is TreeView
select element
).FirstOrDefault();
parent.Remove(container);
if (parentContainer != null)
{
parent.Children[0].Selected = true;
parentContainer.Focus();
}
}
}
e.Handled = true;
}
break;
}
}
}
最后是Container.cs
public class Container : INotifyPropertyChanged
{
private bool m_selected;
private string m_name;
private ObservableCollection<Container> m_children;
private Container m_parent;
public Container(string name)
{
m_name = name;
m_children = new ObservableCollection<Container>();
m_parent = null;
m_selected = false;
}
public event PropertyChangedEventHandler PropertyChanged;
public string Name
{
get
{
return m_name;
}
set
{
m_name = value;
OnPropertyChanged("Name");
}
}
public Container Parent
{
get
{
return m_parent;
}
set
{
m_parent = value;
}
}
public bool Selected
{
get
{
return m_selected;
}
set
{
m_selected = value;
OnPropertyChanged("Selected");
}
}
public ObservableCollection<Container> Children
{
get
{
return m_children;
}
}
private void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public void Add(Container child)
{
m_children.Add(child);
child.Parent = this;
}
public void Remove(Container child)
{
m_children.Remove(child);
child.Parent = null;
}
}
答案 0 :(得分:0)
我自己没有检查过,但我认为你可以通过使用ObservableCollections的CollectionChanged事件来实现这一点。在这里,您可以将一个事件附加到您的子集合中,以便在删除其中一个集合时,您可以将Selected的属性(例如集合的第一个子集)设置为true。类似下面的代码:
附上活动:
Children.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Children_CollectionChanged);
事件实施:
void Children_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
Children.First().Selected = true;
}
}
答案 1 :(得分:0)
我尝试了这里提供的解决方案:"TreeView selected item when removing nodes"并且在一个简单的应用程序中它可以很好地工作。毋庸置疑,在我正在开发的应用程序中不 ......
看看文章的内容,似乎我需要TreeViewItem作为我项目的容器。所以我试过了:
m_tree.ItemContainerGenerator.ContainerFromItem
除此之外总是返回null。然后我读了以下内容:TreeView.ItemContainerGenerator.ContainerFromItem returns null,此时我的大脑几乎吹了一根导火索!
似乎想要选择TreeViewItem,我必须从我的层次结构的顶部开始,然后在树上工作,直到我到达我想要的地方。所以,我的容器数据有一个Parent属性,所以我构建了一堆对象:
Stack<Containerl> stack = new Stack<Container>();
Container toBeSelected = ... my object to be selected after deletion ...
while (toBeSelected != null)
{
stack.Push(toBeSelected);
toBeSelected = toBeSelected.Parent;
}
然后我删除了我的层次结构中的所有项目,然后执行以下操作:
TreeViewItem item = m_tree.ItemContainerGenerator.ContainerFromItem(stack.Pop()) as TreeViewItem;
while(item != null && (stack.Count > 0))
{
item = item.ItemContainerGenerator.ContainerFromItem(stack.Pop()) as TreeViewItem;
}
// Force this item to be selected, and set focus
item.IsSelected = true;
item.Focus();
它有效!!!