Да, можно предположить, что был бы более простой способ сделать это (одно свойство snapToWholeElement). Я тоже не смог найти эту недвижимость.
Чтобы выполнить ваше требование, я написал небольшую логику. По сути, в моем объекте Windows есть открытое свойство lbHeight , которое вычисляет высоту списка, вычисляя высоту каждого отдельного элемента.
Сначала давайте взглянем на XAML:
<Window
x:Class="SO.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="120" SizeToContent="Height"
Title="SO Sample"
>
<StackPanel>
<ListBox x:Name="x_list" Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=lbHeight}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Border x:Name="x" Background="Gray" Margin="4" Padding="3">
<TextBlock Text="{Binding}" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Window>
Обратите внимание, что ItemTemplate несколько не тривиален. Важно отметить, что я дал этому предмету Имя, чтобы найти его позже.
В конструкторе с выделенным кодом я поместил некоторые данные в список:
public MainWindow( )
{
InitializeComponent( );
this.x_list.ItemsSource = Enumerable.Range( 0, 100 );
}
Далее я реализую findVisualItem - чтобы найти корневой элемент шаблона данных. Я сделал эту функцию немного общей, поэтому она получает предикат p , который определяет, является ли это элемент, который я хочу найти:
private DependencyObject findVisualItem( DependencyObject el, Predicate<DependencyObject> p )
{
DependencyObject found = null;
if( p(el) ) {
found = el;
}
else {
int count = VisualTreeHelper.GetChildrenCount( el );
for( int i=0; i<count; ++i ) {
DependencyObject c = VisualTreeHelper.GetChild( el, i );
found = findVisualItem( c, p );
if( found != null )
break;
}
}
return found;
}
Я буду использовать следующий предикат, который возвращает true, если искомый элемент является границей, а его имя - "x". Вам следует изменить этот предикат, чтобы он соответствовал корневому элементу вашего ItemTemplate.
findVisualItem(
x_list,
el => { return ( el is Border ) ? ( (FrameworkElement)el ).Name == "x" : false; }
);
Наконец, свойство lbHeight:
public double lbHeight
{
get {
FrameworkElement item = findVisualItem(
x_list,
el => { return ( el is Border ) ? ( (FrameworkElement)el ).Name == "x" : false; }
) as FrameworkElement;
if( item != null ) {
double h = item.ActualHeight + item.Margin.Top + item.Margin.Bottom;
return h * 12;
}
else {
return 120;
}
}
}
Я также создал окно, реализующее INotifyPropertyChanged, и когда элементы списка были загружены (событие Loaded в ListBox), я вызвал событие PropertyChanged для свойства 'lbHeight'. В какой-то момент это было необходимо, но в конце WPF извлек свойство lbHeight, когда у меня уже есть обработанный элемент.
Возможно, ваши Предметы не одинаковы по высоте, и в этом случае вам нужно будет суммировать все Предметы в VirtualizedStackPanel. Если у вас есть горизонтальная полоса прокрутки, вы должны учитывать ее для общей высоты курса. Но это общая идея. Вы опубликовали свой вопрос всего через 3 часа - я надеюсь, что кто-то придет с более простым ответом.