我写了自己的“Multiselect”--Treeview。它为所有数据绑定项目使用接口ITreeViewItem。如果没有绑定项目将实现此接口,此树视图将不起作用。WPF Multiselect TreeView - 几乎完全实现,但是
public interface ITreeViewItem : INotifyPropertyChanged
{
bool IsExpanded { get; set; }
bool IsSelected { get; set; }
bool IsEnabled { get; set; }
Visibility Visibility { get; set; }
ITreeViewItem GetParentTreeViewItem();
}
这是我的第一个问题:有一个人一个想法如何不强制此接口的实现?它似乎不是干净的。我决定实现这个接口的主要原因是,似乎不可能在没有(最坏的情况下)扩展整棵树的情况下找到与数据项匹配的ItemsControl。在延迟加载数据的情况下会导致加载所有这些数据。
另一个原因是所选项目背景的着色。如果我想突出背景,我需要一些属性来绑定。 IsSelected上的正常触发似乎不起作用,因为一次只有一个项目可以设置此值(或?)。
关于最后一个问题,我已经在这里问WPF TreeViewItem Background给定的答案的问题是,默认的模板没有默认的颜色(第一次点击一个项目的颜色将是轻violett,第二它将是蓝色;这是另一个问题)。那么在树形视图失去焦点后,如何将所有选定的项目的颜色设置为浅灰色或将实际关注的项目设置为蓝色?
如果您需要更多关于我的实现的信息,请随时询问。
编辑:@Snowbear JIM编译:
internal static bool ExecuteOnTreeViewItem(this TreeView tree, ITreeViewItem dataItem, Action<TreeViewItem> action)
{
Stack<ITreeViewItem> pathToRoot = GetPathToRoot(dataItem);
TreeViewItem firstVisibleItem = tree.SyncTreeLevels(pathToRoot);
if (firstVisibleItem == null)
return false; // can't find any item in path which is currently selectable
if (pathToRoot.Count != 0) // expand the first item if nextLevelItems will follow
firstVisibleItem.IsExpanded = true;
ExecuteOnTreeViewItem(tree, pathToRoot, action, firstVisibleItem);
return true;
}
private static void ExecuteOnTreeViewItem(TreeView tree, Stack<ITreeViewItem> pathToRoot, Action<TreeViewItem> action, TreeViewItem treeViewItem)
{
if (pathToRoot.Count == 0)
{
action(treeViewItem);
return;
}
var nextLevelItem = pathToRoot.Pop();
if (pathToRoot.Count != 0)
nextLevelItem.IsExpanded = true; // make children visible to create the item containers
if (treeViewItem.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
{
EventHandler eventHandler = null;
if (!treeViewItem.IsExpanded)
treeViewItem.IsExpanded = true;
eventHandler = delegate
{
if (treeViewItem.ItemContainerGenerator.Status == GeneratorStatus.Error
|| treeViewItem.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
treeViewItem.ItemContainerGenerator.StatusChanged -= eventHandler;
if (treeViewItem.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
var nextTreeViewItem = treeViewItem.ItemContainerGenerator.ContainerFromItem(nextLevelItem) as TreeViewItem;
ExecuteOnTreeViewItem(tree, pathToRoot, action, nextTreeViewItem);
}
};
treeViewItem.ItemContainerGenerator.StatusChanged += eventHandler;
}
else
{
var nextTreeViewItem = treeViewItem.ItemContainerGenerator.ContainerFromItem(nextLevelItem) as TreeViewItem;
ExecuteOnTreeViewItem(tree, pathToRoot, action, nextTreeViewItem);
}
}
internal static Stack<ITreeViewItem> GetPathToRoot(ITreeViewItem item)
{
Stack<ITreeViewItem> items = new Stack<ITreeViewItem>();
ITreeViewItem parent = item;
while (parent != null)
{
items.Push(parent);
parent = parent.GetParentTreeViewItem();
}
return items;
}
/// <summary>
/// Returns the first item in stack which is visible in tree view. This is used
/// for the case that the first Item of ITreeViewItem is not the first bound item
/// </summary>
/// <param name="tree"></param>
/// <param name="hierachyItems"></param>
/// <returns></returns>
internal static TreeViewItem SyncTreeLevels(this TreeView tree, Stack<ITreeViewItem> hierachyItems)
{
TreeViewItem item = null;
while (item == null && hierachyItems.Count > 0)
item = tree.ItemContainerGenerator.ContainerFromItem(hierachyItems.Pop()) as TreeViewItem;
return item;
}
这段代码坏事是,该操作是留在继承的TreeViewItem调用事件后,才执行...但它的工作原理。
如果类型不正确,您可以检查ItemSource的类型并引发异常。关于第二种 - 不要使用ListViewItem类的IsSelected属性,尝试使用事件并以某种方式设置项目的IsSelected属性。 – vorrtex 2011-04-01 19:16:36
我使用一些想法创建了一个多选树视图。检查它在这里:http://stackoverflow.com/a/13412801/166452 – 2012-11-16 08:22:24