18

Ok, so here is my XAML:

<TextBlock Text="{Binding Path=InstanceName}"></TextBlock>

If InstanceName is null or an empty string, I want Visibility="Collapsed". Otherwise I want Visibility="Visible". How would I do that?

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447

5 Answers5

50

You could use a ValueConverter:

<TextBlock 
     Visibility="{Binding InstanceName, Converter={local:StringNullOrEmptyToVisibilityConverter}}" 
     Text="{Binding InstanceName}"/>

with the following codebehind:

public class StringNullOrEmptyToVisibilityConverter : System.Windows.Markup.MarkupExtension, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return string.IsNullOrEmpty(value as string) 
            ? Visibility.Collapsed : Visibility.Visible;
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {            
        return this;
    }
}
Markus Hütter
  • 7,796
  • 1
  • 36
  • 63
  • I can see that working, but that's going to get really tedious fast. I can't help but think there is got to be a better way. – Jonathan Allen Jan 23 '10 at 17:48
  • 6
    what do you think would be the tedious part? do you think setting both visibility and text seperately could get tedious? or do you think so of valueconverters in general? one thing i would change is binding the visibility property with relativesource to self with path=Name so that you don't repeat "InstanceName"! other than that I don't see how this could get tedious (you could always write your own MarkupExtensions or even a Behaviour that could do this, but i'd think it's over the top and a valueconverter would be just the right thing) – Markus Hütter Jan 23 '10 at 18:20
3

If you are inside a (Data-)Template you can use Triggers for that.

Otherwise, the MVVM-Pattern or a ValueConverter will help you.

Matthias
  • 12,053
  • 4
  • 49
  • 91
2

By putting an extra property in your viewmodel that you can bind the Visibility attribute to:

public class ViewModel
{
   public string InstanceName {...}
   public Visibility InstanceVisibility 
   { 
      get 
      {
           return String.IsNullOrEmpty(InstanceName) ? Visibility.Collapsed : Visibility.Visible;
      }
}
karmjit singh
  • 229
  • 3
  • 14
Peter Lillevold
  • 33,668
  • 7
  • 97
  • 131
  • 1
    I don't like that. The model needs to be shared by multiple views, but the behavior is only needed for this one. – Jonathan Allen Jan 23 '10 at 17:28
  • 3
    Imo there is a one-to-one relationship between views and viewmodels. If you have views that share some common functionality you could extract the common pieces, and perhaps put those in a common viewmodel superclass. – Peter Lillevold Jan 23 '10 at 22:06
  • That doesn't sound right. I'm not familiar with 'ViewModels', but with classic MVC multiple views can bind to the same instance of a model. In that way you can edit in one Window and see it updated in real time in another. – Jonathan Allen Jan 25 '10 at 01:44
  • 4
    You're right about MVC. Though in MVVM the viewmodel is _not_ the same thing as the Model. Looking at the abbreviation: Model-View-ViewModel, you have the first piece, the Model, is our business data. The View is exactly what it says. Then the ViewModel is the bridge between the two. The viewmodel is "a model for a view", that is a specific view of the Model tailored for a specific view. Yes, you can have several viewmodels working against the same Model. IMO seldom do you have an über viewmodel serving multiple views. – Peter Lillevold Jan 25 '10 at 08:00
1
<TextBlock Text="{Binding Path=InstanceName},FallbackValue={x:Null}"></TextBlock>

Then add a DataTrigger to check the value is null and change visibility using Setter. This is the simple method which iam using.

Kishore Kumar
  • 21,449
  • 13
  • 81
  • 113
0

Ok, so this is close with PyBinding:

<TextBlock Text="{Binding Path=InstanceName}" Visibility="{p:PyBinding BooleanToVisibility(IsNotNull($[.InstanceName]))}"  ></TextBlock>

I need to replace IsNotNull with something that means IsNotNullOrEmpty, but I'm getting closer.

Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447