我寫了自己的「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