How can one obtain the panel that is used within a TreeView
? I've read that by default TreeView
uses a VirtualizingStackPanel
for this. When I look at a TreeView
template, all I see is <ItemsPresenter />, which seems to hide the details of what panel is used.
Possible solutions:
1) On the treeview instance ("tv"), from code, do this: tv.ItemsPanel.
The problem is, this does not return a panel, but an ItemsPanelTemplate ("gets or sets the template that defines the panel that controls the layout of the items").
2) Make a TreeView template that explicitly replaces <ItemsPresenter /> with your own ItemsControl.ItemsPanel. I am providing a special template anyways, so this is fine in my scenario. Then give a part name to the panel that you place within that template, and from code you can obtain that part (i.e. the panel). The problem with this? see below.
(I am using a control named VirtualTreeView which is derived from TreeView, as is seen below):
<ControlTemplate x:Key="VirtualTreeViewTemplate" TargetType="{x:Type local:VirtualTreeView}">
<Border>
<local:VirtualScrollViewer
Style="{StaticResource VirtualScrollViewer}"
x:Name="PART_VirtualScrollViewer"
CanContentScroll="True">
<!-- instead of: <ItemsPresenter />, use following: -->
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Name="PART_ItemsStackPanel"
IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</local:VirtualScrollViewer>
</Border>
</ControlTemplate>
[I stripped out all clutter here for visibility...]
The problem with this is: thi开发者_开发知识库s immediately overrides any TreeView layout mechanism. Actually, you just get a blank screen, even when you have TreeViewItems filling the tree. Well, the reason I want to get a hold of the panel is to take some part in the MeaureOverride, but without going into all of that, I certainly do not want to rewrite the book of how to layout a treeview. I.e., doing this the step #2 way seems to invalidate the point of even using a TreeView in the first place.
Sorry if there is some confusion here, thanks for any help you can offer.
There is a class called VisualTreeHelper
that allows you to get non-exposed child controls/elements of a control.
Here is a link to the GetChild
method on that class which allows you to enumerate all the children, etc:
http://msdn.microsoft.com/en-us/library/system.windows.media.visualtreehelper.getchild.aspx
The following is a supplement to the answer given by David above. This offers a way to get all of the Visual Children that are UIElement
s via an extension method.
public static class WPFXtensions
{
static public IEnumerable<UIElement> GetDescendantUIElements(this UIElement uiElement)
{
int childrenCnt = VisualTreeHelper.GetChildrenCount(uiElement);
for (int i = 0; i < childrenCnt; i++)
{
Visual childVisual = VisualTreeHelper.GetChild(uiElement, i) as Visual;
if(childVisual == null)
continue;
if (childVisual is UIElement)
{
yield return childVisual as UIElement;
// note: by recursively calling within the loop, we walk the tree all the way down for each
// UIElement encountered before moving to the next UIElement sibling.
foreach (UIElement e in GetDescendantUIElements(childVisual as UIElement))
yield return e;
}
}
}
}
// Use this then like this to retrieve an expected child StackPanel
StackPanel sp1 = (StackPanel)this.GetDescendantUIElements()
.First(uiElem => uiElem is StackPanel);
// Get all of this UIElement's descendants (for a diagnostic look);
// In a run where this was a TreeView, 78 UIElements returned
List<UIElement> uiElements = this.GetDescendantUIElements().ToList();
精彩评论