C#WPF - 带有DataTemplate的ListBox - 添加额外的"标题"行

时间:2018-06-14 21:43:37

标签: c# wpf data-binding listbox

我有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>

我的课程具有名称,饮用等属性。它位于列表&lt;&gt;中设置为DataSource。这部分工作正常。

但我需要在此ListBox中添加额外的条目,该条目将在DataTemplate之前显示。它将没有绑定或相同的结构 - 它将作为标题,并将具有与DataTemplate不同的布局。 有什么办法吗?如果我像普通的ListBox一样添加它,那么我会在使用绑定之前得到一个ListBox必须为空的错误。

现在ListBox看起来像这样: enter image description here

但我需要让它看起来像这样: enter image description here

有可能这样做吗?如果有办法使用除ListBox之外的其他元素,我可以使用它,只要我可以使用Binding和DataTemplate。

2 个答案:

答案 0 :(得分:0)

如果scrollign并不重要,您只需在列表框上方放置一个静态边框即可。 对于要在滚动中包含该额外行的场景,您必须修改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>

事实上,通过覆盖控件的模板,您可以为其提供所需的所有自定义...您可以更改任何其他任何控件的文本块。

答案 1 :(得分:0)

您可以使用Stackpanel或Grid实现此目标。但是,如果您坚持在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();
    }
}

要向集合中添加不同的对象,请根据您的继承设置将类型更改为对象或类型。

enter image description here