views:

158

answers:

2

I have what I thought was a simple requirement, but I'm having difficulty working out how to do it.

I'm binding to an address (Line1, Line2, Line3, Line4 for example)

What I want to do is display

Line1
Line2
Line3
Line4

But if any line is empty or null, I'd like to 'collapse':

Line1
Line3
Line4

I've tried a StackPanel with TextBlocks - but I haven't worked out how to get the TextBlocks to 'disappear' if they're empty.

<StackPanel>
    <TextBlock Text="{Binding Line1}"></TextBlock>
    <TextBlock Text="{Binding Line2}"></TextBlock>
    <TextBlock Text="{Binding Line3}"></TextBlock>
    <TextBlock Text="{Binding Line4}"></TextBlock>
</StackPanel>

I've also tried MultiBinding, but I can't work out how to get a newline in the StringFormat.

<TextBlock>
    <TextBlock.Text>
        <!-- Doesn't work: "System.FormatException" -->
        <MultiBinding StringFormat="{}{1}\n{2}\n{3}\n{4}"> 
            <Binding Path="Line1"/>
            <Binding Path="Line2"/>
            <Binding Path="Line3"/>
            <Binding Path="Line4"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

Any ideas?

+1  A: 

It would be easiest just to aggregate all these properties into another readonly one that you bind to:

<TextBlock Text="{Binding Address}"/>

However, you could also bind the Visibility of each TextBlock:

<TextBlock Text="{Binding Line1}" Visibility="{Binding Line1, Converter={StaticResource TextVisibilityConverter}}"/>

The TextVisibilityConverter would return Visibility.Collapsed if the value is null or empty.

HTH, Kent

Kent Boogaart
It amazes me how the things that I think are going to be easier in WPF always turn out to be complicated. Unfortunately the converse is not always the case :(
Benjol
+2  A: 

This is a bit ugly, but it works. I've defined a style with a trigger that collapses a TextBlock if its Text is an empty string:

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type TextBlock}">
            <Style.Triggers>
                <DataTrigger 
                    Binding="{Binding Text,RelativeSource={RelativeSource Self}}" 
                    Value="">
                    <Setter Property="Visibility" Value="Collapsed" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </StackPanel.Resources>
    <TextBlock Text="{Binding Line1}" />
    <TextBlock Text="{Binding Line2}" />
    <TextBlock Text="{Binding Line3}" />
    <TextBlock Text="{Binding Line4}" />
</StackPanel>
Matt Hamilton
It IS ugly, but I think I prefer it, because I don't want my class to have to worry about how it's data is going to be displayed.
Benjol
Also, if you don't want to eliminate any global style applied to TextBlock, add BasedOn="{StaticResource {x:Type TextBlock}}" to your style declaration (I think I've got that right).
Matt Hamilton
@Benjol: if you're using MVVM, this becomes a lot more natural. It means your VM worries about how things are displayed and it would have the read-only property to do the aggregation.
Kent Boogaart
OK, I'm accepting the answer as the one that I like. Greater minds than mine may care to disagree...
Benjol