受 Fëanor 的回答的启发,我试图让创建TreeViewItem
a 的每个数据项都易于访问TreeViewItem
。
这个想法是向TreeViewItem
视图模型添加一个 -typed 字段,也通过接口公开,并在创建容器TreeView
时自动填充它。TreeViewItem
这是通过子类TreeView
化并将一个事件附加到 来完成的ItemContainerGenerator
,该事件记录了TreeViewItem
它的创建时间。陷阱包括TreeViewItem
s 是懒惰地创建的,因此在某些时候可能真的没有可用的。
自从发布这个答案以来,我已经进一步开发并在一个项目中使用了很长时间。到目前为止没有任何问题,除了这违反了 MVVM (但也为您节省了大量简单案例的样板文件)。来源在这里。
用法
选择所选项目的父项并将其折叠,确保它在视图中:
...
var selected = myTreeView.SelectedItem as MyItem;
selected.Parent.TreeViewItem.IsSelected = true;
selected.Parent.TreeViewItem.IsExpanded = false;
selected.Parent.TreeViewItem.BringIntoView();
...
声明:
<Window ...
xmlns:tvi="clr-namespace:TreeViewItems"
...>
...
<tvi:TreeViewWithItem x:Name="myTreeView">
<HierarchicalDataTemplate DataType = "{x:Type src:MyItem}"
ItemsSource = "{Binding Children}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
</tvi:TreeViewWithItem>
...
</Window>
class MyItem : IHasTreeViewItem
{
public string Name { get; set; }
public ObservableCollection<MyItem> Children { get; set; }
public MyItem Parent;
public TreeViewItem TreeViewItem { get; set; }
...
}
代码
public class TreeViewWithItem : TreeView
{
public TreeViewWithItem()
{
ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
}
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
var generator = sender as ItemContainerGenerator;
if (generator.Status == GeneratorStatus.ContainersGenerated)
{
int i = 0;
while (true)
{
var container = generator.ContainerFromIndex(i);
if (container == null)
break;
var tvi = container as TreeViewItem;
if (tvi != null)
tvi.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
var item = generator.ItemFromContainer(container) as IHasTreeViewItem;
if (item != null)
item.TreeViewItem = tvi;
i++;
}
}
}
}
interface IHasTreeViewItem
{
TreeViewItem TreeViewItem { get; set; }
}