向 Silverlight 图表添加位置十字准线






4.80/5 (2投票s)
这篇技术博客文章详细介绍了最新版本的 Silverlight 图表的差异,并展示了如何添加位置十字线。
Silverlight 的发展速度很快,真的很快。 最近的 MIX09 大会发布了 Silverlight 3 (Beta) 以及新版本的 Silverlight Toolkit。 所有这些变化都使我们这些博主难以跟上!
一个多月前,我在我的博客上发表了一篇文章,讲述了如何向 Silverlight Toolkit 图表添加位置十字线。 这篇博文简要讨论了上周发布的图表的变化,并相应地更新了代码。
如果你想知道一般方法是如何工作的,我建议阅读之前的博文。 这篇文章是对图表模板如何更改的更新和讨论。
图表发生了一些小的更改,这些更改会影响我之前的实现,包括图表轴上命名空间和方向类型的更改。 但是,最大的变化是图表控件本身的模板。 以前,图表模板通过 Grid
结构化,如下所示
<ControlTemplate TargetType="charting:Chart">
<Grid Name="ChartArea" Style="{TemplateBinding ChartAreaStyle}">
<!-- ##### chart control adds column / row definitions and axes here #### -->
<Grid Height="250" x:Name="PlotArea" Style="{TemplateBinding PlotAreaStyle}">
<!-- the standard chart template components -->
<Grid x:Name="GridLinesContainer" />
<Grid x:Name="SeriesContainer"/>
<Border BorderBrush="#FF919191" BorderThickness="1" />
<!-- ##### I added cross hair and legend here #### -->
</Grid>
</Grid>
</ControlTemplate>
加载模板后,图表会添加轴和相应的列/行定义。 这使我们可以自由地在“PlotArea
”网格中添加新的视觉内容。 使用Silverlight Spy检查视觉树,它看起来像这样
我添加的为了构建十字线和图例的内容以红色突出显示。
Silverlight 工具包的 3 月版本通过引入新的布局面板 EdgePanel
(可以将其视为 DockPanel
!)修改了将轴添加到图表的方式。 此面板允许您将元素定位(或停靠)在面板的四个边缘之一或面板中心。 修改后的控件模板如下所示
<ControlTemplate TargetType="charting:Chart" x:Key="ChartTemplate">
<Grid x:Name="ChartRoot" Style="{TemplateBinding PlotAreaStyle}">
<chartingprimitives:EdgePanel x:Name="ChartArea"
Style="{TemplateBinding ChartAreaStyle}">
<Grid Canvas.ZIndex="1" Style="{TemplateBinding PlotAreaStyle}" />
<Border Canvas.ZIndex="1" BorderBrush="#FF919191" BorderThickness="1" />
<!-- ##### I added cross hair and legend here #### -->
<!-- ##### chart control adds column / row definitions and axes here #### -->
</chartingprimitives:EdgePanel>
</Grid>
</ControlTemplate>
我已指明我添加自己的视觉内容的位置以及图表控件添加轴的位置。 生成的视觉树如下所示
这里显着的区别是图表的所有组件都包含在同一个 EdgePanel
中,它们的位置由它们的 EdgePanel.Edge
属性决定。 这确实给我们带来了一个 Z 轴顺序的问题,以前我们的附加内容位于堆栈顶部,现在它位于中间的某个位置。 幸运的是,EdgePanel
遵守 Canvas.ZIndex
附加属性,允许我们将内容推到顶部。 修改后的完整模板如下所示
<ControlTemplate TargetType="charting:Chart" x:Key="ChartTemplate">
<Grid x:Name="ChartRoot" Style="{TemplateBinding PlotAreaStyle}">
<chartingprimitives:EdgePanel x:Name="ChartArea"
Style="{TemplateBinding ChartAreaStyle}">
<Grid Canvas.ZIndex="-1" Style="{TemplateBinding PlotAreaStyle}" />
<Border Canvas.ZIndex="3" BorderBrush="#FF919191" BorderThickness="1" />
<!-- a location crosshair -->
<Grid Name="CrosshairContainer" Canvas.ZIndex="1" Background="Transparent"
MouseMove="CrosshairContainer_MouseMove"
MouseEnter="CrosshairContainer_MouseEnter"
MouseLeave="CrosshairContainer_MouseLeave" >
<Grid Name="Crosshair">
<Line Name="Vertical" X1="{Binding Path=X}" Y1="0"
X2="{Binding Path=X}" Y2="400" Stroke="Black"/>
<Line Name="Horizontal" X1="0" Y1="{Binding Path=Y}"
X2="400" Y2="{Binding Path=Y}" Stroke="Black"/>
</Grid>
</Grid>
<!-- a location 'legend' -->
<Border Canvas.ZIndex="2" Name="LocationIndicator"
Visibility="Collapsed" Style="{StaticResource LocationLegendStyle}">
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="Location: "/>
<TextBlock Text="{Binding Path=Key,
Converter={StaticResource FormattingConverter},
ConverterParameter=hh:mm:ss}"/>
<TextBlock Text=", "/>
<TextBlock Text="{Binding Path=Value,
Converter={StaticResource FormattingConverter},
ConverterParameter=0.00}"/>
</StackPanel>
</Border>
</chartingprimitives:EdgePanel>
</Grid>
</ControlTemplate>
还有一个更微妙的点,与 Grid
关联的 MouseMove
、MouseLeave
等事件处理程序仅在背景不为 null
时才有效,因此需要透明背景。 我不知道为什么,相信我……它就是有效!
最后一个重要的变化是用于将点从屏幕坐标转换为图表坐标系中的位置的方法。 以前,我在“隐藏的 IRangeAxis
接口上使用了一种名为 GetPlotAreaCoordinateValueRange
的方法。 现在,它已重命名为 GetValueAtPosition
并返回并采用 UnitValue
类型作为其输入(大概是为了 API 与饼图的一致性)。 这是代码
/// <summary>
/// Transforms the supplied position on the plot area grid into a point within
/// the plot area coordinate system
/// </summary>
private KeyValuePair<DateTime, double> GetPlotAreaCoordinates(Point position)
{
IComparable yAxisHit = ((IRangeAxis)YAxis).GetValueAtPosition(
new UnitValue(PlotArea.ActualHeight - position.Y, Unit.Pixels));
IComparable xAxisHit = ((IRangeAxis)XAxis).GetValueAtPosition(
new UnitValue(position.X, Unit.Pixels));
return new KeyValuePair<DateTime, double>((DateTime)xAxisHit, (double)yAxisHit);
}
进行这些更改后,我们的十字线再次可以完全正常工作
… 直到工具包的下一个版本。
你可以从这里下载项目源代码。
此致,
Colin E.