MVVM - hiding a control when bound property is not present
Asked Answered
H

2

17

I was wondering if it is possible to hide a control on a view if the property to which the control is bound does not exist in the view model. For example, if I have the following:

<CheckBox Content="Quote"
          IsChecked="{Binding Path=IsQuoted}" />

Can I detect in XAML that the IsQuoted property does not exist on the view model, and simply hide the control in that instance.

I am essentially creating a wizard dialog that moves through a collection of view models, displaying the associated view for each one. For some of the view models in the collection, the "IsQuoted" property will be present, and for some not.

I would like to have a check box outside of these views that displays when the current view model has the property, and hides when the view model does not. All of the view models are derived from a common base class, but I would rather not clutter the base by adding a "ShowQuoted" property, etc.

Thoughts? And, thanks in advance...

Householder answered 27/3, 2012 at 16:36 Comment(0)
S
42

Handle the case where it the value is present by using a converter which always returns Visibility.Visible. Handle the case where the value isn't present by specifying a fallback value. When the property isn't present the binding fails and receives the fallback value.

<Page.DataContext>
    <Samples:OptionalPropertyViewModel/>
</Page.DataContext>
<Grid>
    <Grid.Resources>
        <Samples:AlwaysVisibleConverter x:Key="AlwaysVisibleConverter" />
    </Grid.Resources>
    <CheckBox 
        Content="Is quoted" 
        IsChecked="{Binding IsQuoted}"
        Visibility="{Binding IsQuoted, 
                     Converter={StaticResource AlwaysVisibleConverter}, 
                     FallbackValue=Collapsed}"
        />
</Grid>
public class OptionalPropertyViewModel
{
    public bool IsQuoted { get; set; }
}
public class AlwaysVisibleConverter : IValueConverter
{
    #region Implementation of IValueConverter

    public object Convert(object value, Type targetType,
                          object parameter, CultureInfo culture)
    {
        return Visibility.Visible;
    }

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

    #endregion
}
Shortchange answered 27/3, 2012 at 16:45 Comment(3)
Cool. I've been using WPF for four years and I never noticed the FallbackValue property (or I did and just didn't pay attention at the time - hard to say). This could come in handy.Sebaceous
If you wanted to be more explicit, you could check for DependencyProperty.UnsetValue msdn.microsoft.com/en-us/library/…Valine
Clever, @Phil! @OwenJohnson, can't check for UnsetValue if the property doesn't exist. UnsetValue is a sentinel value for a property that exists but doesn't have a value. In this case the property doesn't exist on some objects.Placencia
W
0

I've modified Phil's answer to make TargetNullValue work:

public class AlwaysVisibleConverter : IValueConverter
{
    public object? Convert(object? value, Type targetType,
                           object parameter, CultureInfo culture)
    {
        if (value is null)
        {
            // Makes TargetNullValue work.
            // Apparently TargetNullValue doesn't look at the target directly, but through this converter.
            return null;
        }
        return Visibility.Visible;
    }

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

And:

<CheckBox
    Content="Is quoted"
    IsChecked="{Binding IsQuoted}"
    Visibility="{Binding IsQuoted,
                 Converter={StaticResource AlwaysVisibleConverter}, 
                 FallbackValue=Collapsed
                 TargetNullValue=Collapsed}"
    />
Wrac answered 20/3 at 15:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.