Ivan Prodanov
Ivan Prodanov

Reputation: 35502

Why binding does not work?

So i created a userControl with a "ShowCode" property to learn how to use properties. I want this property to hide the second row in the grid.

View:

    <UserControl x:Class="Test.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
    <Grid Margin="0,0,0,0" Name="outergrid" DataContext="{Binding}">
      <Grid.RowDefinitions>
        <RowDefinition Height="3*" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>

    <ContentControl Name="XAMLView" Grid.Row="0"/>
    <GridSplitter ResizeDirection="Rows" 
                Grid.Row="0"
                VerticalAlignment="Bottom" 
                HorizontalAlignment="Stretch" />
    <Border Width="11" Grid.Row="1" Background="Black" />
</Grid>

Code:

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
        outergrid.RowDefinitions[1].SetBinding(RowDefinition.HeightProperty, new Binding() { Path = new PropertyPath("ShowCode"), Source = this, Converter = new BoolToHeightConverter(), ConverterParameter = "True" });
    }

    public bool ShowCode
    {
        get { return (bool)GetValue(ShowCodeProperty); }
        set { SetValue(ShowCodeProperty, value); }
    }

    public static readonly DependencyProperty ShowCodeProperty =
        DependencyProperty.Register("ShowCode",
        typeof(bool),
        typeof(UserControl1),
        new PropertyMetadata(true, new PropertyChangedCallback(OnShowCodeChanged)));

    static void OnShowCodeChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        UserControl1 source = (UserControl1)sender;

        //source.outergrid.RowDefinitions[1].Height = 
    }

    public class BoolToHeightConverter : IValueConverter
    {
        public object Convert(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            if ((string)parameter == "False") return "0";
            return "1*";
        }

        public object ConvertBack(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            if ((int)parameter == 0) return false;
            return true;
        }
    }
}

Problem: When I use it like this:

<xamlviewer:UserControl1 ShowCode="False"/>

Convert(...) is called 2 times and both times the "parameter" is "True", otherwise if ShowCode="True" Convert() is called only once and "parameter" is again "True"

Why is it always true?

Upvotes: 0

Views: 156

Answers (2)

Clemens
Clemens

Reputation: 128062

At least two things are wrong here.

  1. Your converter returns a string where it should return a GridLength.

  2. The value to be converted is passed to the value parameter of the converter, not to parameter and it is a bool.

So you should write this:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    if (value is bool && (bool)value)
    {
        return new GridLength(1, GridUnitType.Star);
    }

    return new GridLength(0);
}

No converter parameter is needed in the binding:

outergrid.RowDefinitions[1].SetBinding(
    RowDefinition.HeightProperty,
    new Binding()
    {
        Path = new PropertyPath("ShowCode"),
        Source = this,
        Converter = new BoolToHeightConverter()
    });

Upvotes: 1

Alex
Alex

Reputation: 23300

Parameter is always true because you made it have that value:

outergrid.RowDefinitions[1].SetBinding(
    RowDefinition.HeightProperty, 
    new Binding() 
    {
        Path = new PropertyPath("ShowCode"), 
        Source = this, 
        Converter = new BoolToHeightConverter(), 
        ConverterParameter = "True" // <---- You are enforcing its value here.
    });

Your Converter is messed up anyway: you have to check value not parameter to properly convert data back and forth:

// NOTE: Your property is BOOL not STRING.
public class BoolToHeightConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, System.Globalization.CultureInfo culture)
    {
        if(value is bool)
            if((bool)value) return new GridLength(1, DataGridLengthUnitType.Star);
            else return new GridLength(0);

        throw new ArgumentException("Not a bool");
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, System.Globalization.CultureInfo culture)
    {
        // You may not need this method at all!
        if(value is GridLength)
            return ((GridLength)value).Value == 0);
        throw new ArgumentException("Not a GridLength");
    }
}

Parameter is not needed anymore (unless you have other needs for it somewhere else).

Upvotes: 1

Related Questions