One of Chart's
most powerful features is the ability to define custom templates for
data-point popups.
In this post, I will cover defining a basic data-point popup, as well as attaching and displaying more complex data.
Start Simple
Start with a
simple chart:
<ca:Chart x:Name="Chart1" XValue="Area" ChartKind="RoundedBlock" Width="600" Height="400">
<ca:Chart.DataSeries>
<ca:Series YValue="Total" />
</ca:Chart.DataSeries>
</ca:Chart>
In your
code-behind, create a simple data class and set your
chart's data-source:
public class ChartData
{
public string Area { get; set; }
public double Total { get; set; }
}
void Chart1_Loaded(object sender, RoutedEventArgs e)
{
Chart1.DataSource = new ChartData[]
{
new ChartData() { Area = "North America", Total = 451 },
new ChartData() { Area = "South America", Total = 466 },
new ChartData() { Area = "Europe", Total = 732 },
new ChartData() { Area = "Asia/Pacific", Total = 4088},
new ChartData() { Area = "Africa", Total = 973 }
};
}
If you compile and run your application, you should now
have a chart that looks like the following:

Define A Custom DataPointPopup
You can add a
custom data-point popup by first defining it as a resource:
<ca:DataPointPopup x:Key="CustomDataPointPopup">
<ca:DataPointPopup.DataTemplate>
<DataTemplate>
<Border Background="#70000000" CornerRadius="4" Padding="10">
<Grid Width="130">
<Border Background="{Binding DataPoint.Brush}" Opacity="0.6" CornerRadius="3" Margin="-5 -2 -5 -2"/>
<TextBlock Text="{Binding DataPoint.X}" Foreground="White" HorizontalAlignment="Left" FontWeight="Bold" />
<TextBlock Text="{Binding DataPoint.Y}" Foreground="White" HorizontalAlignment="Right" FontWeight="Bold" />
</Grid>
</Border>
</DataTemplate>
</ca:DataPointPopup.DataTemplate>
</ca:DataPointPopup>
And then binding
the DataPointPopup property of your series to it:
<ca:Series YValue="Total" DataPointPopup="{StaticResource CustomDataPointPopup}" />
Notice that the template binds to properties of a DataPoint object. In fact, the DataContext of the popup is an instance of the DataPointContext class. As well as providing information about the current DataPoint, it also provides information regarding the Series, Chart and more.
If you compile and run your application, you should now
have a chart that looks like the following:

Attaching And Displaying Complex Data
If we want to display more advanced information in the popup, we can add additional data to each DataPoint
object via its Tag property. Do this by hooking into the Chart's
DataStructureCreated event:
void Chart1_DataStructureCreated(object sender, EventArgs e)
{
Series series = Chart1.DataSeries[0] as Series;
foreach (DataPoint dp in series.DataPoints)
{
switch (dp.X as string)
{
case "North America":
dp.Tag = new ChartData[]
{
new ChartData() { Area = "Canada", Total = 33 },
new ChartData() { Area = "Mexico", Total = 111 },
new ChartData() { Area = "USA", Total = 307 }
};
break;
case "South America":
dp.Tag = new ChartData[]
{
new ChartData() { Area = "Argentina", Total = 40 },
new ChartData() { Area = "Brazil", Total = 191 },
new ChartData() { Area = "Venezuela", Total = 26 },
new ChartData() { Area = "Others", Total = 239 },
};
break;
case "Europe":
dp.Tag = new ChartData[]
{
new ChartData() { Area = "France", Total = 65 },
new ChartData() { Area = "Germany", Total = 82 },
new ChartData() { Area = "UK", Total = 61 },
new ChartData() { Area = "Others", Total = 524 }
};
break;
case "Asia/Pacific":
dp.Tag = new ChartData[]
{
new ChartData() { Area = "China", Total = 1368 },
new ChartData() { Area = "Japan", Total = 127 },
new ChartData() { Area = "India", Total = 1198 },
new ChartData() { Area = "Others", Total = 1395 }
};
break;
case "Africa":
dp.Tag = new ChartData[]
{
new ChartData() { Area = "Egypt", Total = 77 },
new ChartData() { Area = "Morocco", Total = 31 },
new ChartData() { Area = "South Africa", Total = 49 },
new ChartData() { Area = "Others", Total = 816 }
};
break;
}
}
}
Note: Chart.DataStructureCreated is the earliest possible time that you can access the chart's internal data-structures.
Now, we can define
a more advanced DataPointPopup:
<ca:DataPointPopup x:Key="CustomDataPointPopup">
<ca:DataPointPopup.DataTemplate>
<DataTemplate>
<Border Background="#70000000" CornerRadius="4" Padding="10">
<StackPanel Orientation="Vertical">
<Grid Width="130">
<Border Background="{Binding DataPoint.Brush}" Opacity="0.6" CornerRadius="3" Margin="-5 -2 -5 -2"/>
<TextBlock Text="{Binding DataPoint.X}" Foreground="White" HorizontalAlignment="Left" FontWeight="Bold" />
<TextBlock Text="{Binding DataPoint.Y}" Foreground="White" HorizontalAlignment="Right" FontWeight="Bold" />
</Grid>
<ListBox ItemsSource="{Binding DataPoint.Tag}" Margin="0" Padding="0">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="120" Margin="10 0 0 0">
<TextBlock Text="{Binding Area}" Foreground="White" HorizontalAlignment="Left" />
<TextBlock Text="{Binding Total}" Foreground="White" HorizontalAlignment="Right" FontWeight="Bold" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<Grid>
<ItemsPresenter Margin="0" />
</Grid>
</ControlTemplate>
</ListBox.Template>
</ListBox>
</StackPanel>
</Border>
</DataTemplate>
</ca:DataPointPopup.DataTemplate>
</ca:DataPointPopup>
Notice that we can now bind to DataPoint.Tag and use its data to further populate our custom popup.
If you compile and run your application, you should now
have a chart that looks like the following:

Conclusion
By defining a custom DataPointPopup template and utilizing DataPoint's Tag property, you can create a custom
popup that is able display additional information that is as complex and/or diverse as anything you can
imagine! This is one feature that every developer should give adequate attention to!