为什么multibinding总是为第一个值传递DependencyProperty.UnsetValue?

时间:2012-05-16 20:44:56

标签: wpf data-binding binding

在我的WPF应用程序中的一个表单中,我正在构建一个伪造的条形图。条形图由具有12列的网格组成。每列包含一个Rectangle。我正在使用数据绑定将矩形的高度绑定到我想要绘制的数据。 xaml看起来像这样:

<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>

为简洁起见,我只包含一个矩形。

以下是MultiBinding中使用的IMultiValueConverter的代码:

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();
    }

}

最后,这是此控件背后的代码:

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;
    }
}

我已将断点放在if ( values[ 0 ] is string )行的转换器中。我看到values数组中的第一个条目始终是DependencyProperty.UnsetValue。但我知道XML有这个属性的其他数据。我做错了什么?

由于

1 个答案:

答案 0 :(得分:1)

我已经能够解决这个问题了。如果仔细观察第一个多重绑定中的XPath,您会看到它以“}”结尾。该字符实际上不是XPath的一部分,它是绑定的原始文本的剩余部分,当它是使用{Binding Source = {...} XPath = ....}语法的单个绑定时。删除后,我停止获取值数组中第一个值的DependencyProperty.UnsetValue

我还能够解决另一个问题,第二个值为零。我将RectangleHeight属性设为DependencyProperty,并在Loaded事件处理程序中添加了代码,将其设置为等于包含所有Grid的{​​{1}}控件的实际高度。现在我的代码工作了,我得到了一个可爱的条形图。

感谢所有看过的人。