private void treeViewItem_BringIntoView(string findItem)
{
System.Diagnostics. Debug.WriteLine("enter treeViewItem_BringIntoview" );
try
{
_currentSelectedItem.ApplyTemplate();
ItemsPresenter itemsPresenter = (ItemsPresenter)_currentSelectedItem.Template.FindName("ItemsHost", (FrameworkElement)_currentSelectedItem);
if (itemsPresenter != null )
itemsPresenter.ApplyTemplate();
else
_currentSelectedItem.UpdateLayout();
VirtualizingPanel virtualizingPanel = _currentSelectedItem.GetItemsHost() as VirtualizingPanel;
virtualizingPanel.CallEnsureGenerator();
int selectedIndex = -1;
int count1 = _currentSelectedItem.Items.Count;
for (int i = 0; i < count1; i++)
{
ItemsItem1 tviItem = _currentSelectedItem.Items.GetItemAt(i) as ItemsItem1;
if (null != tviItem && tviItem.Label.Equals(findItem))
{
selectedIndex = i;
break;
}
}
if (selectedIndex < 0)
{
return;
}
Action action = () =>
{
TreeViewItem itemSelected = null ;
//Force to generate every treeView item by using scroll item
if (virtualizingPanel != null )
{
try
{
virtualizingPanel.CallBringIndexIntoView(selectedIndex);
}
catch (System.Exception ex)
{
System.Diagnostics. Debug.WriteLine("CallBringIndexIntoView exception : " + ex.Message);
}
itemSelected = (TreeViewItem)_currentSelectedItem.ItemContainerGenerator.ContainerFromIndex(selectedIndex);
}
else
{
itemSelected = (TreeViewItem)_currentSelectedItem.ItemContainerGenerator.ContainerFromIndex(selectedIndex);
itemSelected.BringIntoView();
}
if (null != itemSelected)
{
_currentSelectedItem = itemSelected;
(_currentSelectedItem as TreeViewItem ).IsSelected = true;
_currentSelectedItem.BringIntoView();
}
};
Dispatcher.BeginInvoke( DispatcherPriority.Background, action);
}
catch (System.Exception ex)
{
//
}
}
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d ="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable ="d"
x:Class ="WpfApplication1.MainWindow"
x:Name ="Window"
Title="MainWindow"
Width="640"
Height="480" >
<Window.Resources>
<HierarchicalDataTemplate
x:Key ="ItemsItem1Template"
ItemsSource="{Binding Items}" >
<StackPanel>
<TextBlock
Text="{Binding Label}" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid
x:Name ="LayoutRoot" >
<TreeView
x:Name ="_treeView"
HorizontalAlignment="Left"
Width="287"
d:DataContext ="{Binding}"
ItemsSource="{Binding Items, Source ={StaticResource SampleDataSource }}"
ItemTemplate="{DynamicResource ItemsItem1Template}"
VirtualizingStackPanel.IsVirtualizing ="True"
VirtualizingStackPanel.VirtualizationMode ="Standard"
/>
<Button
x:Name ="btnFind"
Content="Find"
HorizontalAlignment="Right"
Margin="0,8,8,0"
VerticalAlignment="Top"
Width="75"
Click="BtnFind_Click" />
<TextBox
x:Name ="txtContent"
Margin="291,8,87,0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Height="21.837" />
</Grid>
</Window>
public static class WPFUIElementExtension
{
#region Functions to get internal members using reflection
// Some functionality we need is hidden in internal members, so we use reflection to get them
#region ItemsControl.ItemsHost
static readonly PropertyInfo ItemsHostPropertyInfo = typeof (ItemsControl). GetProperty("ItemsHost" , BindingFlags.Instance | BindingFlags. NonPublic);
public static Panel GetItemsHost(this ItemsControl itemsControl)
{
Debug.Assert (itemsControl != null);
return ItemsHostPropertyInfo .GetValue( itemsControl, null ) as Panel;
}
#endregion ItemsControl.ItemsHost
#region Panel.EnsureGenerator
private static readonly MethodInfo EnsureGeneratorMethodInfo = typeof(Panel ).GetMethod( "EnsureGenerator", BindingFlags .Instance | BindingFlags.NonPublic );
public static void CallEnsureGenerator(this Panel panel)
{
Debug.Assert (panel != null);
EnsureGeneratorMethodInfo.Invoke (panel, null);
}
#endregion Panel.EnsureGenerator
#region VirtualizingPanel. BringIndexIntoView
private static readonly MethodInfo BringIndexIntoViewMethodInfo = typeof(VirtualizingPanel ).GetMethod( "BringIndexIntoView", BindingFlags .Instance | BindingFlags.NonPublic );
public static void CallBringIndexIntoView(this VirtualizingPanel virtualizingPanel, int index)
{
Debug.Assert (virtualizingPanel != null);
BringIndexIntoViewMethodInfo.Invoke (virtualizingPanel, new object [] { index });
}
#endregion VirtualizingPanel. BringIndexIntoView
#endregion Functions to get internal members using reflection
}
解决方法2:
(1)参考方法1的第一步解决方法
(2)遍历ItemsControl的Items, 根据ContainerFromIndex去找到当前可见的元素的index。
(3)利用BringInoView去滚动现有的Item以便UI产生后续的子元素, 然后循环直到找见要查找的子元素。(遍历分为2部分,向前遍历和向后遍历)
注意事项:
(1)参考方法1的第一注意事项
(2)因为比方法1多了一次循环遍历,当items很多时有点卡顿,不过还在可以忍受的范围。
具体代码:
1.参考方法1的代码,具体只有强制生成子元素的方法有区别, 即与方法1中的步骤3有区别。
2.如下:
private void treeViewItem_BringIntoView2(string findItem)
{
System.Diagnostics. Debug .WriteLine("enter treeViewItem_BringIntoview" );
try
{
_currentSelectedItem.ApplyTemplate();
ItemsPresenter itemsPresenter = (ItemsPresenter )_currentSelectedItem.Template.FindName( "ItemsHost", (FrameworkElement )_currentSelectedItem);
if (itemsPresenter != null )
itemsPresenter.ApplyTemplate();
else
_currentSelectedItem.UpdateLayout();
VirtualizingPanel virtualizingPanel = _currentSelectedItem.GetItemsHost() as VirtualizingPanel ;
virtualizingPanel.CallEnsureGenerator();
TreeViewItem itemTemp = null ;
ItemsItem1 objTemp = null ;
int visiableIndex = -1;
int findIndex = -1;
int count1 = _currentSelectedItem.Items.Count;
for (int i = 0; i < count1; i++)
{
itemTemp = ( TreeViewItem )_currentSelectedItem.ItemContainerGenerator.ContainerFromIndex(i);
if (null != itemTemp)
{
visiableIndex = i;
}
objTemp = _currentSelectedItem.Items.GetItemAt(i) as ItemsItem1 ;
if (null != objTemp && objTemp.Label.Equals(findItem))
{
findIndex = i;
}
}
if (findIndex == -1 || visiableIndex == -1)
{
return ;
}
if (findIndex < visiableIndex)
{
for (int j = visiableIndex; j >= findIndex; j--)
{
itemTemp = (TreeViewItem )_currentSelectedItem.ItemContainerGenerator.ContainerFromIndex(j);
if (null != itemTemp)
{
itemTemp.BringIntoView();
}
}
}
else if (findIndex > visiableIndex)
{
for (int j = visiableIndex; j <= findIndex; j++)
{
itemTemp = (TreeViewItem )_currentSelectedItem.ItemContainerGenerator.ContainerFromIndex(j);
if (null != itemTemp)
{
itemTemp.BringIntoView();
}
}
}
else
{
itemTemp = (TreeViewItem )_currentSelectedItem.ItemContainerGenerator.ContainerFromIndex(visiableIndex);
if (null != itemTemp)
{
itemTemp.BringIntoView();
}
}
if (null != itemTemp)
{
_currentSelectedItem = itemTemp;
(_currentSelectedItem as TreeViewItem ).IsSelected = true;
_currentSelectedItem.BringIntoView();
}
}
catch (System.Exception ex)
{
//
}
}