如何隐藏空的文本块?

57
在下面提供的 XAML 中,有时我没有 Phone 的值。当发生这种情况时,该值会丢失,但是 TextBlock 仍然占用面板中的空间。我想隐藏空的 TextBlock,使其不在 StackPanel 中占用空间。
<StackPanel>
    <TextBlock Text="{Binding Path=FirstName}" />
    <TextBlock Text="{Binding Path=LastName}" />
    <TextBlock Text="{Binding Path=Phone}" />
    <TextBlock Text="{Binding Path=Email}" />
</StackPanel>

我已经阅读了这篇文章,但是被接受的回答对我不起作用:

<StackPanel>
    <TextBlock Text="{Binding Path=FirstName}" />
    <TextBlock Text="{Binding Path=LastName}" />
    <TextBlock Text="{Binding Path=Phone}">
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Style.Triggers>
                    <Trigger Property="Text" Value="{x:Null}">
                        <Setter Property="Visibility" Value="Collapsed" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
    <TextBlock Text="{Binding Path=Email}" />
</StackPanel>

我是否哪里犯了错误,或者被接受的答案是错的?为达成目标应该怎么做?


当手机被创建或删除时,它的属性是String.Empty还是Null? - Dave White
它是空的。问题已经解决 :) - Boris
3个回答

94

你可能需要使用以下代码:

<Style TargetType="TextBlock">
        <Style.Triggers>
            <Trigger Property="Text" Value="">
                <Setter Property="Visibility" Value="Collapsed" />
            </Trigger>
        </Style.Triggers>
</Style>

或者可能两者都有:

<Style TargetType="TextBlock">
        <Style.Triggers>
            <Trigger Property="Text" Value="">
                <Setter Property="Visibility" Value="Collapsed" />
            </Trigger>
            <Trigger Property="Text" Value="{x:Null}">
                <Setter Property="Visibility" Value="Collapsed" />
            </Trigger>
        </Style.Triggers>
</Style>

1
这会导致一个奇怪的效果,即隐藏了我所有的标签,包括复选框右侧的文本。不太好 :) - Roman Starkov
@RomanStarkov 将<Style>移动到一个更适合您的标签范围的<Resources>元素中(也许是封闭的<StackPanel>),或者使用x:Key,这样只有命名样式才会被应用。 - Dai

46

我倾向于使用一个转换器来处理null或空字符串,而不是为此引入一个特定的样式。

<TextBlock Text="{Binding Foo}"
           Visibility="{Binding Foo, 
                        Converter={StaticResource StringToVisibilityConverter}}" />

其中StringToVisibilityConverter定义如下:

[ValueConversion(typeof(string), typeof(Visibility))]
public class StringToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (string.IsNullOrEmpty((string)value))
        {
            return Visibility.Collapsed;
        }
        else
        {
            return Visibility.Visible;
        }
    }

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

我通常使用“转换器”将数据转换为更适合最终用户的形式,但是你的代码也可以正常工作。不过,对于我的情况,我更喜欢使用我的风格。无论如何,感谢您的回答! - Boris
一般来说,我同意这个观点,但是看看WPF内置的转换器:BooleanToVisibilityConverter。它可以使用布尔值完成你正在做的事情。 - Brad Cunningham
+1 总是很好将执行相同功能的两个触发器压缩成一个。 - CodeNaked
3
您可能是想说 Visibility=... 而不是 Text=...。我已经自作主张地将其更改了。 - Heinzi
2
这是最干净和最直接的解决方案,比冗长的风格更好。但有两个小注释:在许多情况下,String.IsNullOrWhiteSpace() 可能更理想。其次,使用 Visibility="{Binding Path=Text, RelativeSource={RelativeSource Self}, Converter={StaticResource StringValidConverter}}" 来避免对绑定值的直接重复引用。 - Gábor

15

您可以使用 DataTrigger

<TextBlock Text="{Binding Path=Title}">
    <TextBlock.Style>
       <Style TargetType="TextBlock">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Title}" Value="{x:Null}">
                    <Setter Property="Visibility" Value="Collapsed" />
                </DataTrigger>
            </Style.Triggers>
       </Style>
    </TextBlock.Style>
</TextBlock>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接