Use a default value when binding cannot be evaluated because of a null value

18,485

Solution 1

You could use a PriorityBinding:

<TextBlock>
    <TextBlock.Text>
        <PriorityBinding>
            <Binding Path="CurrentCustomer.Name" />
            <Binding Source="---" />
        </PriorityBinding>
    </TextBlock.Text>
</TextBlock>

Okay, for Silverlight it is a probably easier to wrap the element in a wrapper (like a Border). You then have an IValueConverter to convert null to Visibility.Collapsed, and anything else to Visibility.Visible:

public class NullToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value != null ? Visibility.Visible : Visibility.Collapsed;
    }

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

And use it like so:

<Border Visibility="{Binding CurrentCustomer, Converter={StaticResource NullToVisibilityConverter}}">
    <TextBlock Text="You have a car"  Visibility="{Binding CurrentCustomer.HasACar,Converter={StaticResource boolToVisibilityConverter}}" />
</Border>

Solution 2

Hey TargetNullValue and FallbackValue works. May be the version of .NET you are using is wrong.

It requires .NET Framework 3.5 SP1.TargetNullValue and FallbackValue is a new addition to the Binding class

Share:
18,485
Pragmateek
Author by

Pragmateek

My blog: Pragmateek I started programming at the age of 2, built my first computer at 3, invented C++ metaprogramming at 5, graduated from MIT at 9, got my third PHD from Harvard at 11 1/2, run my first startup at 12, declined Fields Medal at 13. My favorite programming language is Malbolge. In my spare time I enjoy playing hydrocrystalophone and theremin, and fixing bugs in the Linux kernel. I'm the man behind the "Jon Skeet" bot. And I'm currently cured for serious mythomania.

Updated on June 12, 2022

Comments

  • Pragmateek
    Pragmateek about 2 years

    is there a way to assign a special value when a binding cannot be evaluated because of a null value in the property path ?

    For instance if I have a property Name in a class Customer and a binding like this :

    {Binding CurrentCustomer.Name}
    

    When CurrentCustomer is null I'd like the binding to produce the string "---".

    "TargetNullValue" and "FallbackValue" don't seem to do the trick.

    Thanks in advance for your help.

    EDIT :

    In fact what I'm trying to do is substituting a new source value in place of the true when it is not available. The real scenario is the following :

    a bool value is used to determine the visibility of a control, but when this value is not attainable I'd like to replace it with "false".

    Here is an illustration that perfectly mimics my real use-case :

    MainPage.xaml.cs :

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace TestSilverlightBindingDefaultValue
    {
        public class BoolToVisibilityConverter : IValueConverter
        {
            #region IValueConverter Members
    
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return (bool)value ? Visibility.Visible : Visibility.Collapsed;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
    
            #endregion
        }
    
        public class Customer
        {
            public bool HasACar
            {
                get;
                set;
            }
        }
    
        public partial class MainPage : UserControl
        {
            public static readonly DependencyProperty CurrentCustomerProperty =
                DependencyProperty.Register("CurrentCustomer", typeof(Customer), typeof(MainPage), null);
    
            public Customer CurrentCustomer
            {
                get { return this.GetValue(CurrentCustomerProperty) as Customer; }
                set { this.SetValue(CurrentCustomerProperty, value); }
            }
    
            public MainPage()
            {
                InitializeComponent();
    
                this.CurrentCustomer = null;
    
                this.DataContext = this;
            }
        }
    }
    

    MainPage.xaml :

    <UserControl x:Class="TestSilverlightBindingDefaultValue.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:local="clr-namespace:TestSilverlightBindingDefaultValue"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <local:BoolToVisibilityConverter x:Key="boolToVisibilityConverter" />
    </UserControl.Resources>
        <StackPanel x:Name="LayoutRoot" Background="White">
        <TextBlock Text="You have a car"  Visibility="{Binding CurrentCustomer.HasACar,Converter={StaticResource boolToVisibilityConverter}}" />
    </StackPanel>
    

    FallbackValue is not the solution because it would only change the generated value and not the source value.

    Abe Heidebrecht has provided the perfect solution for WPF with PriorityBinding but it does not exist in Silverlight.

    FINAL EDIT : The second solution of Abe Heidebrecht, ie wrapping in another element, is working perfectly.

  • Rachel
    Rachel over 13 years
    I didn't know you could do this.... I've always used a DataTrigger checking if value is equal to {x:Null}. Thanks!
  • Pragmateek
    Pragmateek over 13 years
    Thanks, this would effectively be the solution...if I was not using Silverlight 4 that does not seem to support PriorityBinding.
  • Pragmateek
    Pragmateek over 13 years
    Thanks, you're right, but my real scenario is more complex; I'll update my initial question to make it clear.
  • Abe Heidebrecht
    Abe Heidebrecht over 13 years
    I've updated the answer to reflect how to do it in silverlight.
  • Pragmateek
    Pragmateek over 13 years
    Thanks again for your great help but...Silverlight 4 does not seem to support DataTrigger too ! It's very annoying that the support for binding and style is not yet fully implemented. If nobody has another clean solution I'll mark your answer as accepted.
  • Abe Heidebrecht
    Abe Heidebrecht over 13 years
    Haha, I'm an idiot. I updated it so that it will work. It is quite annoying to have to do this every time you need this sort of functionality.