Складной «список» связанных элементов в WPF

У меня есть то, что я считал простым требованием, но мне трудно понять, как это сделать.

Я привязываюсь к адресу (Line1, Line2, Line3, Line4 например)

Что я хочу сделать, это показать

Line1
Line2
Line3
Line4

Но если какая-либо строка пуста или равна нулю, я бы хотел «свернуть»:

Line1
Line3
Line4

Я пробовал StackPanel с TextBlocks, но я не понял, как заставить TextBlocks «исчезнуть», если они пусты.

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

Я также пробовал MultiBinding, но не могу понять, как получить новую строку в 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>

Любые идеи?


person Benjol    schedule 20.08.2009    source источник


Ответы (2)


Это немного некрасиво, но это работает. Я определил стиль с триггером, который сворачивает TextBlock, если его Text является пустой строкой:

<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>
person Matt Hamilton    schedule 20.08.2009
comment
Это уродливо, но я думаю, что предпочитаю это, потому что я не хочу, чтобы мой класс беспокоился о том, как будут отображаться его данные. - person Benjol; 20.08.2009
comment
Кроме того, если вы не хотите удалять какие-либо глобальные стили, применяемые к TextBlock, добавьте в объявление стиля BasedOn={StaticResource {x:Type TextBlock}} (думаю, я правильно понял). - person Matt Hamilton; 20.08.2009
comment
@Benjol: если вы используете MVVM, это становится намного более естественным. Это означает, что ваша виртуальная машина беспокоится о том, как отображаются вещи, и у нее будет свойство только для чтения для выполнения агрегации. - person Kent Boogaart; 20.08.2009
comment
Хорошо, я принимаю ответ как тот, который мне нравится. Более великие умы, чем мой, могут не согласиться... - person Benjol; 20.08.2009

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

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

Однако вы также можете связать Visibility каждого TextBlock:

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

TextVisibilityConverter вернет Visibility.Collapsed, если значение равно null или пусто.

person Kent Boogaart    schedule 20.08.2009
comment
Меня поражает, как вещи, которые, как мне кажется, будут проще в WPF, всегда оказываются сложными. К сожалению, не всегда бывает наоборот :( - person Benjol; 20.08.2009