Этот ответ превратился в монстра, но я прошёл сквозь него, и я думаю, что вы найдете ответ.
Нам нужно каким-то образом использовать VirtualizingStackPanel
как ListBox
.Нам нужно собрать все элементы для отображения (кнопка, два текстовых блока и два набора городских данных) в один перечислимый тип.Настоящая хитрость заключается в том, чтобы определить один из трех шаблонов, используемых для визуализации элементов.
Суть в том, что нам нужно создать новый тип ItemsControl
.Теперь мы можем получить небольшое преимущество, просто признав, что хотим создать очень специфический ItemsControl
, который поддерживает только эту задачу.Во-первых, это «стартер на 10» (справочник по СМИ в Великобритании).
Действительно тупой пример создания элемента управления конкретными элементами: -
public class SwitchingItemsControl : ItemsControl
{
public DataTemplate AlternativeItemTemplate { get; set; }
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
ContentPresenter cp = (ContentPresenter)element;
if (AlternativeItemTemplate != null && (((int)item) & 1) == 1)
cp.ContentTemplate = AlternativeItemTemplate;
else
cp.ContentTemplate = ItemTemplate;
cp.Content = item;
}
}
Этот элемент управления предполагает, что его элементы являютсянабор целых чисел.У него есть AlternativeItemTemplate
, который, если он указан, переключается между нечетным / четным основанием (обратите внимание, что это аспект элемента).
Теперь давайте применим это значение с VirtualizingStackPanel
: -
<UserControl x:Class="CustomVirtualizingPanelInSL.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SilverlightApplication1"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<local:SwitchingItemsControl x:Name="itemsControl" >
<local:SwitchingItemsControl.Template>
<ControlTemplate TargetType="local:SwitchingItemsControl">
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</local:SwitchingItemsControl.Template>
<local:SwitchingItemsControl.ItemTemplate>
<DataTemplate>
<Border CornerRadius="2" BorderBrush="Blue" BorderThickness="1" Margin="2">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding}" />
</Border>
</DataTemplate>
</local:SwitchingItemsControl.ItemTemplate>
<local:SwitchingItemsControl.AlternativeItemTemplate>
<DataTemplate>
<Border CornerRadius="2" BorderBrush="Red" BorderThickness="1" Margin="2">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding}" />
</Border>
</DataTemplate>
</local:SwitchingItemsControl.AlternativeItemTemplate>
<local:SwitchingItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</local:SwitchingItemsControl.ItemsPanel>
</local:SwitchingItemsControl>
</Grid>
</UserControl>
Обратите внимание, что ItemsPanel
использует VirtualizingStackPanel
, и это представлено в ScrollViewer
.
Теперь мы можем дать ему много контента: -
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
itemsControl.ItemsSource = Enumerable.Range(0, 10000);
}
}
}
Если вы переключитесь на стандартную StackPanel
, для загрузки потребуется много времени, тогда как при виртуализации это происходит мгновенно.
Вооружившись этой информацией, вы сможете создать специальный ItemsControlкоторый имеет свойства: -
- ButtonTemplate (DataTemplate)
- HeaderTemplate (DataTemplate)
- TopTenHeaderText (String)
- TopHundredHeaderText (String)
- TopTenSource (
IEnumerable<City>
) - TipHunderedSource (
IEnumerable<City>
)
Теперь вы можете создать одно перечислимое с помощью некоторых методов расширения Linq: -
itemsControl.ItemsSource = Enumerable.Repeat((object)null, 1)
.Concat(Enumerable.Repeat((object)TopTenHeadeText))
.Concat(TopTenSource.Cast<object>())
.Concat(Enumerable.Repeat((object)TopHundredText))
.Concat(TopHundredSource.Cast<object>())
Теперь вам просто нужно переопределить PrepareContainerForItemOverride
и выбрать между ButtonTemplate
(для первого нулевого элемента), the HeaderTemplate
для элемента типа string или ItemTemplate
для элемента типа City
.