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 - самая большая разница, которую вы допустите, и вы по умолчанию, если оно станет больше.

Другие вопросы по тегам