WPF: Как правильно использовать несколько представлений списка в контрольном размере?
Это мой XAML прямо сейчас:
<Window x:Class="GridDemo.SubWindow"
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"
xmlns:local="clr-namespace:GridDemo"
d:DataContext="{d:DesignInstance local:ViewModel, IsDesignTimeCreatable=True}"
mc:Ignorable="d"
Title="Window" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView
ItemsSource="{Binding Animals}"
SelectedItem="{Binding SelectedAnimal}"
Grid.Row="0"/>
<Button
Command="{Binding AddAnimalCommand}"
Content="Add Animal"
HorizontalAlignment="Right"
Grid.Row="1"/>
<ListView
ItemsSource="{Binding Vegetables}"
SelectedItem="{Binding SelectedVegetable}"
Grid.Row="2"/>
<Button
Command="{Binding AddVegetableCommand}"
Content="Add Vegetable"
HorizontalAlignment="Right"
Grid.Row="3"/>
</Grid>
Когда я бегу, это показывает это:
Проблема сразу, она использует слишком много вертикального пространства.
Вещь, которую я люблю и хочу сохранить, состоит в том, что если я уменьшу его, чтобы он был слишком маленьким, чтобы показать оба списка в полном объеме, списки уменьшаются и автоматически добавляются полосы прокрутки, но кнопки остаются видимыми, несмотря ни на что.
Но основная проблема возникает, когда списки просмотра разных размеров. Они всегда будут использовать половину доступного им пространства. Предположим, у меня есть десять животных и пять овощей, и мое окно достаточно высоко, чтобы вмещать 15 предметов. Я бы хотел, чтобы представление списка овощей запрашивало столько места, сколько ему нужно, позволяя представлению списка животных запрашивать все оставшееся пространство. Вместо этого оба списка требуют 50% оставшегося пространства, в результате чего список животных становится слишком маленьким, а список овощей - слишком большим.
Я думаю, что я хочу, чтобы строки списка выглядели как Высота = "Авто", когда для них достаточно места, и вести себя как Высота ="*", когда их нет.
1 ответ
Чтобы получить эффект, который вы ищете, я бы сделал что-то вроде этого:
<Window x:Class="GridDemo.SubWindow" x:Name="win"
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"
xmlns:local="clr-namespace:GridDemo"
d:DataContext="{d:DesignInstance local:ViewModel, IsDesignTimeCreatable=True}"
mc:Ignorable="d"
Title="Window" Width="300">
<Grid x:Name="grd">
<Grid.RowDefinitions>
<RowDefinition>
<RowDefinition.Height>
<MultiBinding Converter="{StaticResource gpc}">
<MultiBinding.Bindings>
<Binding Path="Animals" />
<Binding ElementName="win" Path="ActualHeight" />
</MultiBinding.Bindings>
</MultiBinding>
</RowDefinition.Height>
</RowDefinition>
<RowDefinition Height="Auto"/>
<RowDefinition>
<RowDefinition.Height>
<MultiBinding Converter="{StaticResource gpc}">
<MultiBinding.Bindings>
<Binding Path="Vegetables" />
<Binding ElementName="win" Path="ActualHeight" />
</MultiBinding.Bindings>
</MultiBinding>
</RowDefinition.Height>
</RowDefinition>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView
ItemsSource="{Binding Animals}"
SelectedItem="{Binding SelectedAnimal}"
Grid.Row="0"/>
<Button
Command="{Binding AddAnimalCommand}"
Content="Add Animal"
HorizontalAlignment="Right"
Grid.Row="1"/>
<ListView
ItemsSource="{Binding Vegetables}"
SelectedItem="{Binding SelectedVegetable}"
Grid.Row="2"/>
<Button
Command="{Binding AddVegetableCommand}"
Content="Add Vegetable"
HorizontalAlignment="Right"
Grid.Row="3"/>
</Grid>
</Window>
Я использовал реализацию IMultiValueConverter
генерировать пропорции высоты строки. Он находится в словаре ресурсов с ключом "gpc" и реализован следующим образом:
public class GridProportionConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Count() == 2 && values[0] is ICollection && values[1] is double && ((ICollection)values[0]).Count > 0)
{
ICollection collection = (ICollection)values[0];
double windowHeight = (double)values[1];
if (windowHeight < 350)
{
return new GridLength(1, GridUnitType.Star);
}
return new GridLength(collection.Count, GridUnitType.Star);
}
return new GridLength(1, GridUnitType.Star);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
я использовал ICollection
при условии, что у вас есть какой-то ObservableCollection<T>
для ваших коллекций.
Я считаю, что это работает довольно хорошо, но, очевидно, одна вещь, от которой зависит ListViewItem
будучи примерно одинаковой высоты в каждом ListView
в противном случае вам может понадобиться учитывать разницу в высоте.
Я также добавил немного отказоустойчивости, где, если высота окна опускается ниже определенного значения, пропорция становится 1:1.
Если пропорции когда-либо выходят из-под контроля, например, 300:1, вы всегда можете передать обе коллекции и рассчитать более подходящие пропорции, основываясь на этом, например, вы можете решить, что 4:1 - самая большая разница, которую вы допустите, и вы по умолчанию, если оно станет больше.