01.
public class City
02.
{
03.
public string CityName
04.
05.
get;
06.
set;
07.
}
08.
09.
public List<
Company
> Companies
10.
11.
12.
13.
14.
15.
16.
public class Company
17.
18.
public string CompanyName
19.
20.
21.
22.
23.
24.
Person
> Employee
25.
26.
27.
28.
29.
30.
31.
public class Person
32.
33.
public string Name
34.
35.
36.
37.
38.
public MainWindow()
InitializeComponent();
List<
City
> cities = new List<
>();
for (int i = 0; i <
5000
; i++)
cities.Add(new City() {
CityName
=
"City "
+ i,
Companies
new
List<Company>() });
for (int j = 0; j <
100
; j++)
cities[i].Companies.Add(new Company() {
CompanyName
"Company "
+ j,
Employee
List<Person>() });
for (int k = 0; k < 10; k++)
cities[i].Companies[j].Employee.Add(new Person() { Name = "Name " + k });
MessageBox.Show("Data loaded!");
this.DataContext = cities;
<
Grid
>
local:MyTreeView
ItemsSource
"{Binding}"
local:MyTreeView.ItemTemplate
HierarchicalDataTemplate
"{Binding Companies}"
HierarchicalDataTemplate.ItemTemplate
"{Binding Employee}"
DataTemplate
TextBlock
Text
"{Binding Name}"
/>
</
"{Binding CompanyName}"
"{Binding CityName}"
class MyTreeView : ItemsControl
static MyTreeView()
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyTreeView), new FrameworkPropertyMetadata(typeof(MyTreeView)));
protected override DependencyObject GetContainerForItemOverride()
return new MyTreeViewItem();
class MyTreeViewItem : TreeViewItem
static MyTreeViewItem()
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyTreeViewItem), new FrameworkPropertyMetadata(typeof(MyTreeViewItem)));
Style
TargetType
"{x:Type local:MyTreeView}"
Setter
Property
"ItemsPanel"
Setter.Value
ItemsPanelTemplate
local:MyVirtualizingPanel
"Template"
ControlTemplate
ScrollViewer
ScrollViewer.HorizontalScrollBarVisibility
"Auto"
ScrollViewer.VerticalScrollBarVisibility
CanContentScroll
"True"
ItemsPresenter
"{x:Type local:MyTreeViewItem}"
Grid.RowDefinitions
RowDefinition
Height
"16"
"*"
Grid.ColumnDefinitions
ColumnDefinition
Width
"26"
ToggleButton
IsChecked
"{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=IsExpanded, Mode=TwoWay}"
"{StaticResource ExpandCollapseToggleStyle}"
ClickMode
"Press"
Border
Grid.Column
"1"
Background
"{TemplateBinding Background}"
BorderBrush
"{TemplateBinding BorderBrush}"
BorderThickness
"{TemplateBinding BorderThickness}"
ContentPresenter
ContentSource
"Header"
x:Name
"ItemsPresenter"
Grid.Row
ControlTemplate.Triggers
Trigger
"IsExpanded"
Value
"False"
TargetName
"Visibility"
"Collapsed"
39.
40.
001.
class MyVirtualizingPanel : VirtualizingPanel, IScrollInfo
002.
{ .... ....
010.
/// <
summary
011.
/// Gets the virtualized height value.
012.
/// </
013.
public static double GetVirtualizedHeight(DependencyObject obj)
014.
015.
return (double)obj.GetValue(VirtualizedHeightProperty);
016.
017.
018.
019.
/// Sets the virtualized height value.
020.
021.
public static void SetVirtualizedHeight(DependencyObject obj, double value)
022.
023.
obj.SetValue(VirtualizedHeightProperty, value);
024.
025.
026.
// Using a DependencyProperty as the backing store for VirtualizedHeight. This enables animation, styling, binding, etc...
027.
public static readonly DependencyProperty VirtualizedHeightProperty =
028.
DependencyProperty.RegisterAttached("VirtualizedHeight", typeof(double), typeof(MyVirtualizingPanel), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.Inherits, OnVirtualizedHeightChanged));
029.
030.
031.
/// Notify underneath panels about offset
032.
... ...
099.
100.
/// Removes all those containers that are not visible to user.
101.
102.
private void CleanUp(int startPos, int endPos)
103.
104.
IItemContainerGenerator generator = this.ItemContainerGenerator;
105.
this.InternalChildren.Count
106.
107.
UIElement
element
this
.InternalChildren[i];
108.
int index = ((ItemContainerGenerator)generator).IndexFromContainer(element);
109.
if (index < startPos || index > endPos)
110.
111.
this.RemoveInternalChildRange(i, 1);
112.
generator.Remove(generator.GeneratorPositionFromIndex(index), 1);
113.
i--;
114.
115.
116.
} ... ... 139. /// <summary> 140. /// Provides only the visible containers to the users. 141. /// </summary>
139.
140.
/// Provides only the visible containers to the users.
141.
142.
protected override Size MeasureOverride(Size availableSize)
143.
144.
UIElementCollection children = this.InternalChildren;
145.
146.
...
150.
this.CleanUp(firstVisibleIndex, lastVisibleIndex);
151.
152.
154.
using (generator.StartAt(startGenPos, GeneratorDirection.Forward, true))
155.
156.
for (int i = firstVisibleIndex; i <
lastVisibleIndex
157.
158.
bool newlyRealized;
159.
UIElement child = (UIElement)generator.GenerateNext(out newlyRealized);
160.
161.
if (!children.Contains(child))
162.
163.
if (i - firstVisibleIndex >= children.Count)
164.
165.
this.AddInternalChild(child);
166.
167.
else if (children[i - firstVisibleIndex] != child)
168.
169.
this.InsertInternalChild(i - firstVisibleIndex, child);
170.
171.
172.
173.
generator.PrepareItemContainer(child);
174.
175.
if (i == firstVisibleIndex)
176.
177.
SetVirtualizedHeight(child, this.indent - 16.0 > 0.0 ? this.indent - 16.0 : 0.0);
178.
179.
180.
child.Measure(new Size(double.PositiveInfinity, availableSize.Height - y > 0 ? availableSize.Height - y : 0.0));
181.
183.
x = Math.Max(x, child.DesiredSize.Width);
184.
y += child.DesiredSize.Height;
185.
if (y >= availableSize.Height)
186.
187.
lastVisibleIndex = i;
188.
189.
190.
191.
192.
193.
194.
if (this.IsScrolling)
195.
196.
Size computatedSize = new Size(x, estimatedHeight);
197.
this.viewport = new Size(x, availableSize.Height);
198.
this.extent.Width = this.viewport.Width;
199.
this.extent.Height = computatedSize.Height > this.viewport.Height ? computatedSize.Height : this.viewport.Height;
200.
this.ScrollOwner.InvalidateScrollInfo();
201.
202.
203.
return new Size(x, estimatedHeight);
204.
205.
206.
207.
/// Arranges the visible children to user.
208.
209.
protected override Size ArrangeOverride(Size finalSize)
210.
211.
212.
213.
for (int i = 0; i < children.Count; i++)
214.
215.
UIElement child = children[i];
216.
child.Arrange(new Rect(-this.HorizontalOffset, y, finalSize.Width + this.HorizontalOffset, child.DesiredSize.Height));
217.
218.
219.
220.
return finalSize;
221.
} ... ...