自定义蜘蛛网图或雷达图控件






4.96/5 (21投票s)
一个易于使用的 WPF 蜘蛛(雷达)图控件。
引言
虽然我在网上找到了许多免费的图表组件,但我需要一个简单的蜘蛛图或雷达图控件。如果您不知道什么是雷达图,以下是维基百科对它们的解释:“雷达图是一种图形化方法,用于以二维图表的形式显示多变量数据,其中三个或更多定量变量从同一点开始的轴上表示。轴的相对位置和角度通常不具信息意义。”
由于这是WPF应用程序的一部分,我真的不想使用任何嵌入的Flash图表或使用WinForms的图表。由于这次Google未能帮助我,我决定自己动手做一个。
让我们从最终结果开始,这样您就可以决定是否值得继续阅读。
Using the Code
使用此图表非常简单。只需引用WpfCharts
程序集,然后在您的XAML代码中,您可以这样使用它:
<WpfCharts:SpiderChart Title="Spider chart"
Lines="{Binding Lines}"
Axis="{Binding Axes}"
Minimum="0"
Maximum="1"
Ticks="5"
ShowLegend="True"
LegendLocation="BottomRight"
LegendBackgroundColor="Aquamarine"/>
那么,这些依赖属性是什么意思?
Title
:如果您连这个属性的作用都猜不到,我听说他们正在招聘服务员。Lines
:一个可观察的集合(如果您想动态添加线,否则列表也可以)ChartLine
对象。一个ChartLine
对象包含有关要使用的颜色和数据点的信息。Axis
:您在每个轴(辐条)末端看到的标签。显然,应该有多少个轴就应该有多少个图表线中的点(每个辐条一个点)。实际上,您至少需要三个轴才能创建雷达图。- 沿轴的
Minimum
和Maximum
值。在我的例子中,所有轴都有相同的范围,所以只有一个最小值和最大值。 Ticks
:表示您希望有多少条虚线(刻度线)。ShowLegend
,LegendLocation
和LegendBackgroundColor
也应该很清楚。
请注意,您只能动态添加线,但不能添加轴(辐条)。
作为ChartLine
的示例,请参见下面的示例,其中线的名称、线和填充颜色将在图例中重用。
var chartLine = new ChartLine {
LineColor = Colors.Red,
FillColor = Color.FromArgb(128, 255, 0, 0),
LineThickness = 2,
PointDataSource = new[] { 0.1, 0.2, 0.3, 0.21, 0.6, 0.28, 0.97 },
Name = "Chart 1"
}
关注点
我通常会尽量避免创建WPF自定义控件,因为重新样式化现有控件要容易得多。然而,在这种情况下,我没有看到一个简单的出路,所以让我简要解释一下我的进展。
我从一个空白解决方案开始,添加了一个WPF自定义控件项目(WpfCharts
)和一个WPF应用程序(TestSpiderChart
),该应用程序引用了WpfCharts
。WPF自定义控件项目总是包含一个UserControl1
类,我立即删除了它,以及在Themes\Generic.xaml文件中对它的样式引用。在WpfCharts
中,我添加了一个新的自定义控件(WPF),名为SpiderChart
,它会自动在Generic.xaml中添加一个ControlTemplate
(描述控件的外观和感觉)。
蜘蛛图的主要组成部分是中心辐射布局。很容易找到RadialPanel
的示例,它可以将所有子元素排列成一个圆形。我使用了Jobi Joy的Jobi Joy的示例,但如果您需要一个,也可以看看Jeow Li Huan更高级的版本Jeow Li Huan,它修复了几个边缘情况,并且基于Charles Petzold的。
将RadialPanel
重命名为SpiderChartPanel
后,我添加了几个依赖属性(DP)来设置Minimum、Maximum、Ticks和Lines。顺便说一句,Dr. WPF发布了一套广泛的代码片段。输入dp
并按Tab键即可查看可用DP的概览。我在SpiderChart
类中添加了相同的DP以及更多DP,并更新了Generic.xaml中的控件模板以使用它们。
如果您查看代码,您会发现大部分代码都非常直观。雷达图的实际绘制(带有辐条的背景、刻度线和线条)是通过重写SpiderChartPanel
中的OnRender
方法来完成的。Axis
标签绑定到SpiderChartPanel
的ItemsSource
DP,因此我们可以使用Generic.xaml中的ItemTemplate
来设置样式和绘制它们。
但是,我遇到了两个小问题:首先,我注意到SpiderChartPanel
中的OnRender
方法只被调用一次,在子集合设置之前(因此没有绘制任何内容)。因此,我在MeasureOverride
中添加了一个对InvalidateVisual()
的调用,这样OnRender
就可以在子集合设置后被调用。我很确定这不是最佳实践,我尝试使用DP的FrameworkPropertyMetadata
选项之一(AffectsRender
)来实现这一点,但徒劳无功。有人有什么建议吗?
另一个问题是我希望能够动态添加Lines
。如果Lines
绑定到ItemsSource
DP,那么这将开箱即用,但在这种情况下,Panel
的ItemsSource
已经被Axis
标签占用了。因此,我需要创建一个第二个DP,它充当图表线的ItemsSource
。这实际上非常简单,如您在此处所见,事件处理程序只需要再次调用OnRender
来重绘控件。您可以通过单击“添加行”按钮来查看它。
// Add handler in case the Lines collection implements INotifyCollectionChanged
var newValueINotifyCollectionChanged = (e.NewValue as IEnumerable) as INotifyCollectionChanged;
if (newValueINotifyCollectionChanged != null)
newValueINotifyCollectionChanged.CollectionChanged += target.LinesCollectionChanged;
就这样,各位。编码愉快!
历史
- 2012年8月25日:文章v1提交