Я пытаюсь настроить ListBox / ListView с заголовком, чтобы при прокрутке вниз заголовок уменьшался соответственно до некоторой минимальной высоты и оставался там, пока содержимое все еще прокручивается вверх.И затем, когда я прокручиваю содержимое вниз, в некоторой точке рядом с первым элементом, заголовок также будет расширен до его максимальной высоты, когда список прокручивается до позиции 1. Я мог бы добиться этого, изменив ScrollViewer внутри ListView.
Вот стиль ListView:
<Style x:Key="CustomListView" TargetType="ListView">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListView">
<Border Name="Border">
<local:ScrollViewerWithHeader>
<ItemsPresenter/>
</local:ScrollViewerWithHeader>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Вот стиль ScrollViewerWithHeader:
<Style TargetType="{x:Type local:ScrollViewerWithHeader}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="HeaderHeight" Value="192"/>
<Setter Property="MinHeaderHeight" Value="48"/>
<Setter Property="MarginTopOfScrolledContent" Value="144"/>
<Setter Property="Header" Value="{StaticResource SampleGrid}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ScrollViewerWithHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Grid.Column="1" BorderThickness="0,1,1,1">
<Border.BorderBrush>
<SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
</Border.BorderBrush>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Height="{TemplateBinding MinHeaderHeight}"/>
<Border Grid.Row="1" Height="{TemplateBinding MarginTopOfScrolledContent}"/>
<ScrollContentPresenter CanContentScroll="{TemplateBinding CanContentScroll}" Grid.Row="1" Grid.RowSpan="2">
<ScrollContentPresenter.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{TemplateBinding ScrollViewer.Content}" Margin="0,144,0,0"/>
</DataTemplate>
</ScrollContentPresenter.ContentTemplate>
</ScrollContentPresenter>
<ContentControl Grid.Row="0" VerticalAlignment="Top" Grid.RowSpan="2" Template="{TemplateBinding Header}" Height="{TemplateBinding HeaderHeight}"/>
</Grid>
</Border>
<ScrollBar x:Name="PART_VerticalScrollBar"
Value="{TemplateBinding VerticalOffset}"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Grid.Column="2"/>
<ScrollBar x:Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Grid.Row="1"
Grid.Column="1"
Value="{TemplateBinding HorizontalOffset}"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
В блоке кода выше вы можете видеть, что у меня есть Margin = "0,144,0,0 "для Контента внутри ScrollContentPresenter, который должен сначала оставаться прямо над элементами в ListView, а затем прокручиваться вверх по мере прокрутки элементов вверх.Но это работает только тогда, когда виртуализация пользовательского интерфейса отключена.Когда он включен, поле остается там постоянно, и только элементы увеличиваются, поэтому сверху есть пробел.
Вот код C # для ScrollViewerWithHeader:
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace TestListAutoResizingHeader
{
public class ScrollViewerWithHeader : ScrollViewer
{
public double MaxHeaderHeight
{
get { return (double)GetValue(MaxHeaderHeightProperty); }
set { SetValue(MaxHeaderHeightProperty, value); }
}
public static readonly DependencyProperty MaxHeaderHeightProperty =
DependencyProperty.RegisterAttached(
"MaxHeaderHeight",
typeof(double),
typeof(ScrollViewerWithHeader));
public double MinHeaderHeight
{
get { return (double)GetValue(MinHeaderHeightProperty); }
set { SetValue(MinHeaderHeightProperty, value); }
}
public static readonly DependencyProperty MinHeaderHeightProperty =
DependencyProperty.RegisterAttached(
"MinHeaderHeight",
typeof(double),
typeof(ScrollViewerWithHeader));
public object Header
{
get { return GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register(
"Header",
typeof(object),
typeof(ScrollViewerWithHeader),
new FrameworkPropertyMetadata((object)null));
public double HeaderHeight
{
get { return (double)GetValue(HeaderHeightProperty); }
set { SetValue(HeaderHeightProperty, value); }
}
public static readonly DependencyProperty HeaderHeightProperty =
DependencyProperty.Register(
"HeaderHeight",
typeof(double),
typeof(ScrollViewerWithHeader));
public double MarginTopOfScrolledContent
{
get { return (double)GetValue(MarginTopOfScrolledContentProperty); }
set { SetValue(MarginTopOfScrolledContentProperty, value); }
}
public static readonly DependencyProperty MarginTopOfScrolledContentProperty =
DependencyProperty.Register(
"MarginTopOfScrolledContent",
typeof(double),
typeof(ScrollViewerWithHeader));
protected override void OnScrollChanged(ScrollChangedEventArgs e)
{
Console.WriteLine("Header height before: " + HeaderHeight);
if (192 - e.VerticalOffset > 48)
HeaderHeight = 192 - e.VerticalOffset;
else
HeaderHeight = 48;
base.OnScrollChanged(e);
}
}
}
Этот фрагменткод выглядит очень запутанным, но я хочу сделать следующее: поместить немного места прямо над первым элементом ListView, и когда я прокручиваю, он поднимется вместе с элементами.В этом ListView должна быть включена виртуализация пользовательского интерфейса.Кроме того, решение помещать первый фиктивный элемент в ItemsSource и связывать высоту ListViewItem не требуется, так как это не элегантно.
Если вы хотите увидеть это в действии, вы можете открыть приложение Groove Music -> MyМузыка -> Исполнители -> Выберите исполнителя, у которого есть несколько песен -> Просмотр композиций -> Прокрутите вверх, чтобы увидеть эффект.
Я открыт для любых дальнейших вопросов.