同时,我通过创建
MoveSelectionUp()
和
MoveSelectionDown()
上的扩展方法
TreeView
. 我从工具箱的控制代码中的一些私有方法复制了实现,并对私有方法或受保护的方法进行了一些细微的更改。多亏了工具包中提供的所有扩展方法,现在不再那么困难了。
因为它很大程度上不是我的,所以如果未来的访客偶然发现同样的问题,我在此提供下面的代码。
不过,我不想回答这个问题,因为我仍然想更一般地知道,事件是否可以在dependencyobject框架中转发。
树状延伸
:
using System;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
static public class TreeViewExtensions
{
static public void SetSelectedContainerIfValid(this TreeView self, TreeViewItem itm)
{
Contract.Requires(self != null);
if (itm != null)
{
self.SetSelectedContainer(itm);
}
}
static public void MoveSelectionUp(this TreeView self)
{
Contract.Requires(self != null);
var itm = self.GetSelectedContainer();
if (itm == null)
{
self.SetSelectedContainerIfValid(self.GetContainers().LastOrDefault());
}
else
{
self.SetSelectedContainerIfValid(itm.GetContainerAbove());
}
}
static public void MoveSelectionDown(this TreeView self)
{
Contract.Requires(self != null);
var itm = self.GetSelectedContainer();
if (itm == null)
{
self.SetSelectedContainerIfValid(self.GetContainers().FirstOrDefault());
}
else
{
self.SetSelectedContainerIfValid(itm.GetContainerBelow());
}
}
}
TreeView项目扩展
:
using System;
using System.Diagnostics.Contracts;
using System.Windows;
using System.Windows.Controls;
static public class TreeViewItemExtensions
{
static public TreeViewItem GetContainerBelow(this TreeViewItem self)
{
return TreeViewItemExtensions.GetContainerBelow(self, true);
}
/// <summary>
/// Find the next focusable TreeViewItem below this item.
/// </summary>
/// <param name="recurse">
/// A value indicating whether the item should recurse into its child
/// items when searching for the next focusable TreeViewItem.
/// </param>
/// <returns>The next focusable TreeViewItem below this item.</returns>
static public TreeViewItem GetContainerBelow(this TreeViewItem self, bool recurse)
{
Contract.Requires(self != null);
// Look for the next item in the children of this item (if allowed)
if (recurse && self.IsExpanded && self.HasItems)
{
TreeViewItem item = self.ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem;
if (item != null)
{
return item.IsEnabled ?
item :
item.GetContainerBelow(false);
}
}
// Look for the next item in the siblings of this item
ItemsControl parent = self.GetParentTreeViewItem() as ItemsControl ?? self.GetParentTreeView();
if (parent != null)
{
// Get the index of this item relative to its siblings
TreeViewItem item = null;
int index = parent.ItemContainerGenerator.IndexFromContainer(self);
int count = parent.Items.Count;
// Check for any siblings below this item
while (index++ < count)
{
item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem;
if (item != null && item.IsEnabled)
{
return item;
}
}
// If nothing else was found, try to find the next sibling below
// the parent of this item
TreeViewItem parentItem = self.GetParentTreeViewItem();
if (parentItem != null)
{
return parentItem.GetContainerBelow(false);
}
}
return null;
}
/// <summary>
/// Find the last focusable TreeViewItem contained by this item.
/// </summary>
/// <returns>
/// The last focusable TreeViewItem contained by this item.
/// </returns>
static public TreeViewItem GetLastContainer(this TreeViewItem self)
{
Contract.Requires(self != null);
TreeViewItem item = self;
TreeViewItem lastItem = null;
int index = -1;
// Walk the children of the current item
while (item != null)
{
// Ignore any disabled items
if (item.IsEnabled)
{
// If the item has no children, it must be the last
if (!item.IsExpanded || !item.HasItems)
{
return item;
}
// If the item has children, mark it as the last known
// focusable item so far and walk into its child items,
// starting from the last item and moving toward the first
lastItem = item;
index = item.Items.Count - 1;
}
else if (index > 0)
{
// Try searching for the previous item's sibling
index--;
}
else
{
// Stop searching if we've run out of children
break;
}
// Move to the item's previous sibling
item = lastItem.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem;
}
return lastItem;
}
/// <summary>
/// Find the previous focusable TreeViewItem above this item.
/// </summary>
/// <returns>
/// The previous focusable TreeViewItem above this item.
/// </returns>
static public TreeViewItem GetContainerAbove(this TreeViewItem self)
{
Contract.Requires(self != null);
ItemsControl parent = self.GetParentTreeViewItem() as ItemsControl ?? self.GetParentTreeView();
if (parent == null)
{
return null;
}
// Get the index of the current item relative to its siblings
int index = parent.ItemContainerGenerator.IndexFromContainer(self);
// Walk the previous siblings of the item to find a focusable item
while (index-- > 0)
{
// Get the sibling
TreeViewItem item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem;
if (item != null && item.IsEnabled)
{
// Get the last focusable descendent of the sibling
TreeViewItem last = item.GetLastContainer();
if (last != null)
{
return last;
}
}
}
return parent as TreeViewItem;
}
}