Null To Boolean IValueConverter not working

10,544

Solution 1

The real problem is the fact you are not initializing your data objects in the first place. Don't "fix", do it right to begin with; builders are good (for example). You also should be making ViewModels/DataModels rather than working with your Models (database, etc) directly.

public class MyObjectBuilder
{
     Checked _checked;

     public  MyObjectBuilder()
     {
          Reset()
     }

     private void Reset()
     { 
          _checked = new Checked(true); //etc
     }

     public MyObjectBuilder WithChecked(bool checked)
     {
          _checked = new Checked(checked);
     }

     public MyObject Build()
     {
         var built = new MyObject(){Checked = _checked;} 
         Reset();
         return built;
     }
}

then always initialise with the builder

myObjects.Add(new MyObjectBuilder().Build());

or

myObjects.Add(_injectedBuilder.Build()); // Initialises Checked to default 
myObjects.Add(_injectedBuilder.WithChecked(true).Build()); //True

While this doesn't fix your asked problem, it will fix your underlying problem in a way you can Unit Test. i.e. you can test to ensure the values added into your object list are always initialized.

Solution 2

Hmm, why using a converter, if you can have it out of the box?

<CheckBox IsChecked="{Binding VarianceDescriptionProvided, TargetNullValue=False}" />

For more information, pls have a look here.

Share:
10,544
mcalex
Author by

mcalex

Updated on July 28, 2022

Comments

  • mcalex
    mcalex almost 2 years

    How do I use an IValueConverter to convert nulls into booleans?

    I'm using wpf to try to display a bunch of boolean values (in checkboxes). When a new record is created, these values are null, and appear as 'indeterminate' in the checkboxes. I want the nulls to appear and save as 'false' values.

    I tried to create a NullToBoolean converter that takes null values from the database and displays them as false, and then saves them as false when the user hits save. (Essentially, I'm trying to avoid the user having to click twice in the checkboxes (once to make it true, then again to make it false). This seems to work on import - ie null values are shown as false - but unless I do the two-click dance the value doesn't change in the database when I save.

    My Converter:

    [ValueConversion(typeof(bool), typeof(bool))]
    public class NullBooleanConverter : IValueConverter
    {
    
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      {
        if (value != null)
        {
          return value;
        }
        return false;
      }
    
      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      {
        if (value != null)
        {
          return value;
        }
        return null;
      }
    }
    

    One of the checkboxes I'm trying to have the Converter work with:

        <CheckBox Grid.Column="1" Grid.Row="0" Padding="5" Margin="5" VerticalAlignment="Center" Name="chkVarianceDescriptionProvided" IsThreeState="False">
          <CheckBox.IsChecked>
            <Binding Path="VarianceDescriptionProvided" Mode="TwoWay">
              <Binding.Converter>
                <utils:NullBooleanConverter />
              </Binding.Converter>
            </Binding>
          </CheckBox.IsChecked>
        </CheckBox>
    

    I don't know if the problem is because my code is wrong, or if it's a case of the Converter thinking that nothing has changed, therefore it doesn't need to ConvertBack. I have tried all the Modes and switched code in Convert with ConvertBack, but nothing seems to work.

    Can someone point out what I need to do to fix this?

  • Meirion Hughes
    Meirion Hughes over 11 years
    Will fail if you have items added at random times; You would need to add an observable list, listen to it and fix any new item added to it. You may as well just ensure they are correct when you make them.
  • Eli Arbel
    Eli Arbel over 11 years
    Simply run this code every time you get a result from EF. No need for complex wrappers and such
  • mcalex
    mcalex over 11 years
    I didn't know about TargetNullValue, many thanks. However, this doesn't save the 'False' values back to the database (ie, they are still NULL after saving). It does the same job as the converter currently does, so I'll use this instead while I fix my bigger problem.
  • mcalex
    mcalex over 11 years
    Thanks @Meirion-Hughes. I see what you mean, and can follow your ideas to get where I want to be. Defaults in object construction - on it. I didn't know about mvvm when I started on this, so it's currently wpf done old-skool (event handlers, a bit of spaghetti, data validation etc in code-behind) with mvvm features added as I learn how to fit them in. Aiming to make my next project fully mvvm, but have to work through the current hybrid I've got going on this one. Thanks again
  • DHN
    DHN over 11 years
    Ok, was just a try. I wasn't sure, if the value is passed to VM. Thanks for keeping me informed. :)
  • mcalex
    mcalex over 11 years
    Is interesting, because the doco: (msdn.microsoft.com/en-us/library/…) says it is a getter and setter - but then doesn't give a setting example.
  • DHN
    DHN over 11 years
    Well yes the property TargetNullValue itself has a getter and setter. That's why you can pass a value to it. But it still doesn't ensure that the value is passed through the binding to the VM. By thinking about it, it makes a deeper sense. With the TargetNullValue you're giving the view the opportunity to interpret a NULL without interfering the underlying VM or data, which might be processed in a sofisticated logic. It sticks to the principle of decoupling. :)
  • Meirion Hughes
    Meirion Hughes over 11 years
    Google, Caliburn Micro. Its awesome.
  • mcalex
    mcalex over 11 years
    I've investigated a few frameworks. Unfortunately none of them detail how to turn spaghetti into mvvm. Caliburn certainly does look pretty impressive, and might be what I start the new project on. Cheers