How can you get a XAML TextBlock to collapse when it contains no data?
Asked Answered
A

4

17

I want to tell WPF: "If TextBlock contains no data, then don't show it."

TRY #1 with a simple trigger produces the error "'Text' member is not valid because it does not have a qualifying type name.":

<StackPanel Margin="10">
    <TextBlock Padding="10" Background="Yellow" Text="{Binding MainMessage}">
        <TextBlock.Triggers>
            <Trigger Property="Text" Value="{x:Null}">
                <Setter Property="Visibility" Value="Collapsed"/>
            </Trigger>
        </TextBlock.Triggers>
    </TextBlock>
</StackPanel>

TRY #2 with a style trigger produces the error The type 'style' does not contain a public type-converter class:

<UserControl x:Class="TestItemsSource234.Views.SmartForm"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <Style x:Key="MainMessageStyle" TargetType="TextBlock">
            <Style.Triggers>
                <Trigger>
                    <Trigger Property="Text" Value="{x:Null}">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </Trigger>
                </Trigger>
            </Style.Triggers>
        </Style>
    </UserControl.Resources>
    <StackPanel Margin="10">        
        <TextBlock Style="MainMessageStyle" Padding="10" Background="Yellow" Text="{Binding MainMessage}"/>
    </StackPanel>
</UserControl>

TRY #3 with a style DataTrigger produces the same error The type 'style' does not contain a public type-converter class:

<UserControl x:Class="TestItemsSource234.Views.SmartForm"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <Style x:Key="MainMessageStyle" TargetType="TextBlock">
            <Style.Triggers>
                <Trigger>
                    <DataTrigger Binding="{Binding MainMessage}" Value="{x:Null}">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </Trigger>
            </Style.Triggers>
        </Style>
    </UserControl.Resources>
    <StackPanel Margin="10">        
        <TextBlock Style="MainMessageStyle" Padding="10" Background="Yellow" Text="{Binding MainMessage}"/>
    </StackPanel>
</UserControl>

TRY #4: OK, that was a dumb oversight of mine, forgot the StaticResource, but even then both Try #2 and Try #3 get a new error The type System.Windows.Trigger in Style is unknown:

<UserControl x:Class="TestItemsSource234.Views.SmartForm"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <Style x:Key="MainMessageStyle" TargetType="TextBlock">
            <Style.Triggers>
                <Trigger>
                    <Trigger Property="Text" Value="">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </Trigger>
                </Trigger>
            </Style.Triggers>
        </Style>
    </UserControl.Resources>
    <StackPanel Margin="10">        
        <TextBlock Style="{StaticResource MainMessageStyle}" Padding="10" Background="Yellow" Text="{Binding MainMessage}"/>
    </StackPanel>
</UserControl>

So how do I do this?

ANSWER:

OK, so that was a maddening syntax hunt with a happy end, here's the version that works, hope it helps somebody, lessons learned:

  • if trigger, then style
  • if style, then StaticResource
  • if binding, then DataTrigger

code that works:

<UserControl x:Class="TestItemsSource234.Views.SmartForm"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <UserControl.Resources>
        <Style x:Key="MainMessageStyle" TargetType="TextBlock">
            <Style.Triggers>
                <DataTrigger Binding="{Binding MainMessage}" Value="{x:Null}">
                    <Setter Property="Visibility" Value="Collapsed"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </UserControl.Resources>
    <StackPanel Margin="10">
        <ItemsControl
            ItemsSource="{Binding DataTypeViews}"/>
        <TextBlock Style="{StaticResource MainMessageStyle}" Padding="10" Background="Yellow" Text="{Binding MainMessage}"/>
    </StackPanel>
</UserControl>
Antagonist answered 8/6, 2009 at 14:56 Comment(2)
ugh. why is wpf so awful?Ashling
There is no excuse for the WPF team for why #4 does not just WORK! Why is WPF so cryptic?Manuel
M
2

Either Try #2 or Try #3 should be fine - the problem is in the line where you are referencing the style - you need to use either 'Style="{StaticResource [KeyName]}"' or 'Style="{DynamicResource [KeyName]}"'.

Try this (in Try #2):

<StackPanel Margin="10">        
    <TextBlock Style="{StaticResource MainMessageStyle}" Padding="10" Background="Yellow" Text="{Binding MainMessage}"/>
</StackPanel>

In Try 1 you reveal a limitation of current WPF versions: Triggers are not supported directly on elements.

Mazard answered 8/6, 2009 at 15:5 Comment(1)
"Triggers are not supported directly on elements." - Then the compiler should tell you this, not another unrelated error.Manuel
K
6

The easiest, simplest and quickest way are converters. So, why not KISS? (keep it simple, stupid)?

To implement converter classes only a few lines of code are necessary.

Converter:

public class StringToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return string.IsNullOrWhiteSpace((string)value) ? Visibility.Collapsed : Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var visiblity = (Visibility)value;
        return visiblity == Visibility.Visible;
    }
}

Usage:

Include namespace: xmlns:c="clr-namespace:Hfr.Windows.Controls"

Define resource: <c:StringToVisibilityConverter x:Key="StringToVisiblity"/>

Use it:

<TextBlock
    Text="{Binding SomeStringPropertyValue}"
    TextWrapping="Wrap"
    Visibility="{Binding SomeStringPropertyValue, Converter={StaticResource StringToVisiblity}}" />

Since you'll use your converters in multiple projects, implement the converter classes in a "common library".

Kop answered 28/3, 2013 at 8:25 Comment(0)
M
2

Either Try #2 or Try #3 should be fine - the problem is in the line where you are referencing the style - you need to use either 'Style="{StaticResource [KeyName]}"' or 'Style="{DynamicResource [KeyName]}"'.

Try this (in Try #2):

<StackPanel Margin="10">        
    <TextBlock Style="{StaticResource MainMessageStyle}" Padding="10" Background="Yellow" Text="{Binding MainMessage}"/>
</StackPanel>

In Try 1 you reveal a limitation of current WPF versions: Triggers are not supported directly on elements.

Mazard answered 8/6, 2009 at 15:5 Comment(1)
"Triggers are not supported directly on elements." - Then the compiler should tell you this, not another unrelated error.Manuel
M
1

I think the simplest way to do this would be to define a Converter which converts string to visibility.

   ...

   return string.IsNullOrEmpty(s) ? Visibility.Collapsed : Visibility.Visible;
}

Then just

<TextBlock Visibility="{StaticResource StringToVisibilityConverter}"
Manuel answered 27/7, 2010 at 17:7 Comment(0)
R
0

My Solution for VB.net

Public Class ContentToVisibilityConverter
            Implements IValueConverter
        
            Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
                If value Is Nothing OrElse (TypeOf value Is String AndAlso String.IsNullOrWhiteSpace(DirectCast(value, String))) Then
                    Return Visibility.Collapsed 
                End If
                Return Visibility.Visible 
            End Function
        
            Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
                Throw New NotImplementedException()
            End Function
End Class

XAML

<Window.Resources>
     <ResourceDictionary>
<ContentToVisibilityConverter x:Key="ContentToVisibilityConverter"/>
 </Window.Resources>

<TextBlock Text="{Binding Path=MyText,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
              Visibility="{Binding Path=MyText, Converter={StaticResource ContentToVisibilityConverter}}"
              ></TextBlock>
Radiosonde answered 16/7, 2024 at 11:31 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.