views:

26

answers:

1

I have a ListBox control in WPF which contains items of variable height (predominantly a large text block, so it's also affected by word wrapping). Since scrolling behaves badly when the height of an individual item gets too high (especially when close to the height of the ListBox itself), I want to constrain the max height of the individual items.

I've done that readily enough, by using a Style to set the MaxHeight of the ListBoxItem container.

My problem is that I would like to detect that an individual item has hit that constraint, and then style it differently.

This was my first attempt:

<Style x:Key="LogContainerStyle" TargetType="{x:Type ListBoxItem}">
    <Setter Property="MaxHeight" Value="64" />
    <EventSetter Event="MouseDoubleClick" Handler="LogEntry_MouseDoubleClick" />
</Style>
<DataTemplate x:Key="LogTemplate">
    <Grid>
        <TextBlock Text="{Binding Message}" />
        <TextBlock x:Name="More" Text="(more)"
                   HorizontalAlignment="Right" VerticalAlignment="Bottom"
                   Foreground="DarkGray" Visibility="Collapsed" />
    </Grid>
    <DataTemplate.Triggers>
        <Trigger ... height capped at MaxHeight? ...>
            <Setter TargetName="More" Property="Visibility" Value="Visible" />
        </Trigger>
    </DataTemplate.Triggers>
</DataTemplate>

But I'm not sure how to write the trigger. Alternatives welcome.

+1  A: 

Try the code below. I set the ListBoxItem.MaxHeight to 99. I then added a trigger in the DataTemplate that checks the ActualHeight of the root element in the template (i.e. "bd" below) and if it's 99, I change the BorderBrush. Hope this helps.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        ShowActivated="False"
        Title="MainWindow" Height="350" Width="525">
    <ListBox x:Name="lb">
        <ListBox.ItemsSource>
            <x:Array Type="{x:Type sys:Double}">
                <sys:Double>250</sys:Double>
                <sys:Double>100</sys:Double>
                <sys:Double>50</sys:Double>
                <sys:Double>25</sys:Double>
                <sys:Double>99</sys:Double>
                <sys:Double>120</sys:Double>
            </x:Array>
        </ListBox.ItemsSource>
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="MaxHeight" Value="99"/>
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Border x:Name="bd" BorderBrush="Black" BorderThickness="1">
                    <TextBlock Text="{Binding}" Height="{Binding}" Background="LightGray"/>
                </Border>
                <DataTemplate.Triggers>
                    <Trigger SourceName="bd" Property="ActualHeight" Value="99">
                        <Setter TargetName="bd" Property="BorderBrush" Value="Red"/>
                    </Trigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Window>
karmicpuppet
Thanks, that gave me the hint I needed -- I'd already thought about using ActualHeight, but wasn't sure where to get it from. In my case, I stuck a Name on the parent Grid, which did what I wanted. Of course, the downside to this approach is that the specific height value can't be bound, which would have been better. Still, this is sufficient for now.
Miral