Reputation: 8594
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
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