Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 975
Pragmateek Avatar asked Nov 23 '10 18:11

Pragmateek


2 Answers

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>
like image 152
Abe Heidebrecht Avatar answered Sep 30 '22 21:09

Abe Heidebrecht


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

like image 45
Gurucharan Balakuntla Maheshku Avatar answered Sep 30 '22 20:09

Gurucharan Balakuntla Maheshku