Tony Vitabile
Tony Vitabile

Reputation: 8594

Why is the multibinding always passing DependencyProperty.UnsetValue for the first value?

In a form in my WPF application, I am building a psuedo bar graph. The bar graph consists of a Grid with 12 columns. Each column contains a Rectangle. I am using databinding to bind the height of the rectangle to the data that I want to graph. The xaml looks like this:

<Border BorderBrush="{DynamicResource ControlBorder}"
        BorderThickness="2"
        Grid.Column="1"
        Grid.Row="0"
        Margin="0,5"
        Name="SNRGraphBorder">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Rectangle Fill="{DynamicResource TextForeground}"
                   Grid.Column="0"
                   Margin="1,5,2,0"
                   Name="Data01"
                   VerticalAlignment="Bottom">
            <Rectangle.Height>
                <MultiBinding Converter="{StaticResource ScaleData}">
                    <Binding Source="{StaticResource XmlProvider}"
                             XPath="a:PathToData}" />
                    <Binding Path="RectangleHeight"
                             RelativeSource="{RelativeSource AncestorType={x:Type cs:MyControl}}" />
                </MultiBinding>
            </Rectangle.Height>
        </Rectangle>
        . . .
    </Grid>
</Border>

I've only included one rectangle for brevity.

Here's the code for the IMultiValueConverter used in the MultiBinding:

public class ScaleDataConverter : IMultiValueConverter {

    public object Convert( object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
        double snr = 0.0;

        if ( values[ 0 ] is string ) {
            snr = double.Parse( values[ 0 ] as string );

        } else if ( values[ 0 ] is int || values[ 0 ] is double || values[ 0 ] is long || values[ 0 ] is float ) {
            snr = (double) values[ 0 ];
        } else {
            return values[ 0 ];
        }

        double ActualHeight = (double) values[ 1 ];
        return snr * ActualHeight / 99.0;
    }

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

}

Finally, here's the code behind for this control:

public partial class MyControl : UserControl {

    public XmlDataProvider DataProvider { get; set; }

    public DeviceMonitor DeviceMonitor { get; set; }

    public double RectangleHeight {
        get { return SNRGraphBorder.ActualHeight; }
    }

    public MyControl() {
        InitializeComponent();
        DataProvider = Resources[ "XmlProvider" ] as XmlDataProvider; 
    }

    private void GetDiagnosticsInfo() {
        if ( DeviceMonitor != null ) {
            XmlDocument diagnosticsDoc = new XmlDocument();
            string info = DeviceMonitor.GetDiagnosticInfo();
            diagnosticsDoc.LoadXml( info );
            DataProvider.Document = diagnosticsDoc;
        }
    }

    private void RefreshButton_Click( object sender, RoutedEventArgs e ) {
        GetDiagnosticsInfo();
        e.Handled = true;
    }
}

I've put breakpoints into the converter on the if ( values[ 0 ] is string ) line. I see that the first entry in the values array is always DependencyProperty.UnsetValue. Yet I know that the XML has other data for this property. What am I doing wrong?

Thanks

Tony

Upvotes: 0

Views: 1521

Answers (1)

Tony Vitabile
Tony Vitabile

Reputation: 8594

I've been able to resolve the issue. If you look closely at the XPath in the first multi binding, you'll see that it ends in a "}". That character is not actually a part of the XPath, it is a left-over from the original text for the binding when it was a single binding using the {Binding Source={...} XPath=....} syntax. Once I removed it, I stopped getting DependencyProperty.UnsetValue for the first value in the values array.

I was also able to resolve the other issue with the second value being zero. I made the RectangleHeight property a DependencyProperty and added code in the Loaded event handler to set it equal to the actual height of the Grid control that contains all of the Rectangles. Now my code works and I get a lovely bar graph.

Thanks all who looked.

Upvotes: 1

Related Questions