C # WPF - ListBox с DataTemplate - добавить дополнительную строку заголовка

У меня есть ListBox с DataTemplate, например:

 <ListBox ItemsSource="{Binding}" BorderBrush="Transparent" 
         Grid.IsSharedSizeScope="True"
         HorizontalContentAlignment="Stretch"
         Grid.Row="1"
         Grid.Column="0" Grid.ColumnSpan="4"         
         Name="playerList">          
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Black" BorderThickness="2">
                        <Grid Margin="4">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="3*" />
                                <ColumnDefinition Width="3*" />
                                <ColumnDefinition Width="3*" />
                                <ColumnDefinition Width="3*" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="{Binding Name}" FontWeight="Bold" FontSize="16"  />
                            <TextBlock Grid.Column="1" Text="{Binding Drinked }" FontWeight="Bold" FontSize="16" />
                            <TextBlock Grid.Column="2" Text="{Binding Remaining }" FontWeight="Bold" FontSize="16" />
                            <Button Grid.Column="3" Name="addButton" Click="addButton_Click" FontWeight="Bold" FontSize="16">+</Button>
                            <Button Grid.Column="4" Name="substractButton" Click="substractButton_Click" FontSize="16">-</Button>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

У меня есть класс со свойствами Name, Drinked и т. Д. Он в List ‹> установлен как DataSource. Эта часть работает нормально.

Но мне нужно добавить дополнительную запись в этот ListBox, которая будет отображаться перед DataTemplate. У него не будет привязок или такой же структуры - он будет служить заголовком и будет иметь другой макет, чем DataTemplate. Есть ли способ это сделать? Если я добавляю его, как в обычном ListBox, я получаю сообщение об ошибке, что ListBox должен быть пустым перед использованием привязки.

Теперь ListBox выглядит так:  введите описание изображения здесь

Но мне нужно, чтобы это выглядело так:  введите описание изображения здесь

Возможно ли это сделать? Если есть способ сделать это, используя другой элемент, кроме ListBox, меня это устраивает, если я могу использовать Binding и DataTemplate.


person Adam Ježek    schedule 14.06.2018    source источник
comment
Вы хотите, чтобы этот элемент прокручивался вместе со списком? Или он должен быть статичным?   -  person Shawn Kendrot    schedule 15.06.2018
comment
@ShawnKendrot не имеет значения   -  person Adam Ježek    schedule 15.06.2018


Ответы (2)


Если прокрутка не имеет значения, вы можете просто поставить статическую рамку прямо над списком. Для сценария, в котором вы хотите включить эту дополнительную строку в прокрутку, вам необходимо изменить шаблон ListBox. Вот пример неявного стиля, который добавит TextBlock непосредственно перед вашими элементами и будет участвовать в прокрутке:

        <Style TargetType="{x:Type ListBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBox}">
                        <ScrollViewer x:Name="ScrollViewer">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <TextBlock Text="I am an extra row" Grid.Row="0"/>
                                <ItemsPresenter Grid.Row="1"/>
                            </Grid>
                        </ScrollViewer>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Фактически, переопределив шаблон элемента управления, вы можете дать ему все необходимые настройки ... Вы можете изменить текстовый блок для любого другого элемента управления, который вам нужен ...

person taquion    schedule 14.06.2018

Вы можете достичь этой цели, используя стековую панель или сетку. Однако, если вы настаиваете на использовании дополнительной строки в ListBox, вы можете воспользоваться селектором шаблонов содержимого. В следующем решении я использовал триггер для установки шаблона текущего элемента в соответствии с его типом.

    <Window.Resources>
    <local:ObjectToTypeConverter x:Key="ObjectToTypeConverter" />

    <ControlTemplate x:Key="emptyRow">
        <Grid HorizontalAlignment="Stretch">
            <Border Height="50" BorderBrush="Black" BorderThickness="2">
                <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Extra row that is not part of the binding or DataTemplate" />
            </Border>
        </Grid>
    </ControlTemplate>
    <ControlTemplate x:Key="default">
            <Border BorderBrush="Black" BorderThickness="2">
                <Grid Margin="4">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="3*" />
                        <ColumnDefinition Width="3*" />
                        <ColumnDefinition Width="3*" />
                        <ColumnDefinition Width="3*" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Name}" FontWeight="Bold" FontSize="16"  />
                    <TextBlock Grid.Column="1" Text="{Binding Drinked }" FontWeight="Bold" FontSize="16" />
                    <TextBlock Grid.Column="2" Text="{Binding Remaining }" FontWeight="Bold" FontSize="16" />
                    <Button Grid.Column="3" Name="addButton" Click="addButton_Click" FontWeight="Bold" FontSize="16">+</Button>
                    <Button Grid.Column="4" Name="substractButton" Click="substractButton_Click" FontSize="16">-</Button>
                </Grid>
            </Border>
    </ControlTemplate>

    <Style x:Key="ItemStyle" TargetType="{x:Type ListBoxItem}">
        <Setter Property="Template" Value="{DynamicResource emptyRow}" />
    <Style.Triggers>
            <DataTrigger Binding="{Binding ., Converter={StaticResource ObjectToTypeConverter}}" Value="{x:Type local:Model}">
                <Setter Property="Template" Value="{DynamicResource default}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

<Grid>
    <ListBox ItemsSource="{Binding}" BorderBrush="Transparent"
     Grid.IsSharedSizeScope="True"
     HorizontalContentAlignment="Stretch"
     Grid.Row="1"
     ItemContainerStyle="{StaticResource ItemStyle}"
     Grid.Column="0" Grid.ColumnSpan="4"
     Name="playerList" />
</Grid>

Конвертер просто преобразует объект в его тип

    public class ObjectToTypeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value?.GetType();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Чтобы добавить различные объекты в коллекцию, измените тип на объект или на тип в соответствии с настройками наследования.

введите описание изображения здесь

person Thomas Christof    schedule 14.06.2018