If there are multiple players on a chart is it possible to have a unified tooltip that displays the current Y value of each layer currently in contact with the vertical crosshair without having to have the cursor touching each layer individually?
The following is a modified version to support storing the values in a single item type:
<UserControl.Resources> <local:TestData x:Key="data" /> <DataTemplate x:Key="tooltipTemplate"> <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="5" Background="White" IsHitTestVisible="False" Padding="5"> <ItemsControl ItemsSource="{Binding}"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <ContentPresenter Content="{Binding}" ContentTemplate="{Binding Series.LegendItemBadgeTemplate}" /> <TextBlock Text="Series: " /> <TextBlock Text="{Binding Series.Title}" /> <TextBlock Text=" " /> <TextBlock Text="Value: " /> <TextBlock Text="{Binding Value}" /> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Border> </DataTemplate> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <igChart:XamDataChart CrosshairVisibility="Visible"> <local:ChartBehaviors.CursorTooltip> <local:CursorTooltipBehavior TooltipTemplate="{StaticResource tooltipTemplate}" /> </local:ChartBehaviors.CursorTooltip> <igChart:XamDataChart.Axes> <igChart:CategoryXAxis x:Name="xAxis" ItemsSource="{StaticResource data}" Label="{}{Date}" > </igChart:CategoryXAxis> <igChart:NumericYAxis x:Name="yAxis" MinimumValue="0" /> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:ColumnSeries x:Name="columnSeries" Title="Column 1" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ItemsSource="{StaticResource data}" ValueMemberPath="Value1" /> <igChart:ColumnSeries x:Name="columnSeries2" Title="Column 2" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ItemsSource="{StaticResource data}" ValueMemberPath="Value2" /> </igChart:XamDataChart.Series> </igChart:XamDataChart> </Grid> </UserControl>
And code behind:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } } public class TestData : ObservableCollection<TestDataItem> { public TestData() { Add(new TestDataItem() { Label = "A", Value1 = 1, Value2 = 4 }); Add(new TestDataItem() { Label = "B", Value1 = 2, Value2 = 3 }); Add(new TestDataItem() { Label = "C", Value1 = 3, Value2 = 2, }); Add(new TestDataItem() { Label = "D", Value1 = 4, Value2 = 1 }); } } public class TestDataItem { public string Label { get; set; } public double Value1 { get; set; } public double Value2 { get; set; } } public class ChartBehaviors : DependencyObject { public static readonly DependencyProperty CursorTooltipProperty = DependencyProperty.RegisterAttached("CursorTooltip", typeof(CursorTooltipBehavior), typeof(ChartBehaviors), new PropertyMetadata(null, (o, e) => CursorTooltipChanged( o as XamDataChart, e.OldValue as CursorTooltipBehavior, e.NewValue as CursorTooltipBehavior))); public static CursorTooltipBehavior GetCursorTooltip( DependencyObject target) { return target.GetValue(CursorTooltipProperty) as CursorTooltipBehavior; } public static void SetCursorTooltip( DependencyObject target, CursorTooltipBehavior behavior) { target.SetValue(CursorTooltipProperty, behavior); } private static void CursorTooltipChanged( XamDataChart chart, CursorTooltipBehavior oldValue, CursorTooltipBehavior newValue) { if (chart == null) { return; } if (oldValue != null) { oldValue.OnDetach(chart); } if (newValue != null) { newValue.OnAttach(chart); } } } public class SeriesItemInfo : INotifyPropertyChanged { private Series _series; public Series Series { get { return _series; } set { _series = value; if (PropertyChanged != null) { PropertyChanged( this, new PropertyChangedEventArgs("Series")); } } } private object _item; public object Item { get { return _item; } set { _item = value; if (PropertyChanged != null) { PropertyChanged( this, new PropertyChangedEventArgs("Item")); } } } private object _value; public object Value { get { return _value; } set { _value = value; if (PropertyChanged != null) { PropertyChanged( this, new PropertyChangedEventArgs("Value")); } } } public event PropertyChangedEventHandler PropertyChanged; } public class SeriesItemInfoCollection : ObservableCollection<SeriesItemInfo> { public void UpdateSeriesItem( Series series, object item) { bool found = false; var indexes = from curr in this where curr.Series == series select this.IndexOf(curr); object value = null; if (item != null && series != null) { var inf = item.GetType() .GetProperty( ((AnchoredCategorySeries)series) .ValueMemberPath); if (inf != null) { value = inf.GetValue(item, null); } } foreach (int index in indexes) { found = true; this[index].Item = item; this[index].Value = value; } if (!found) { this.Add( new SeriesItemInfo() { Series = series, Item = item, Value = value }); } } } public class CursorTooltipBehavior { private bool _isOverChart = false; private Popup _popup = new Popup(); private ContentControl _content = new ContentControl(); private Panel _container; private XamDataChart _owner = null; private DataTemplate _tooltipTemplate; private SeriesItemInfoCollection _items = new SeriesItemInfoCollection(); public DataTemplate TooltipTemplate { get { return _tooltipTemplate; } set { _tooltipTemplate = value; _content.ContentTemplate = _tooltipTemplate; } } protected bool IsOverChart { get { return _isOverChart; } set { bool last = _isOverChart; _isOverChart = value; if (_isOverChart && !last) { ShowPopup(); } if (!_isOverChart && last) { HidePopup(); } } } private void HidePopup() { _popup.IsOpen = false; } private void ShowPopup() { _popup.IsOpen = true; } public void OnAttach(XamDataChart chart) { if (_owner != null) { OnDetach(_owner); } chart.MouseLeave += Chart_MouseLeave; chart.MouseMove += Chart_MouseMove; chart.SeriesCursorMouseMove += Chart_SeriesCursorMouseMove; _popup.IsOpen = false; _popup.Child = _content; _content.ContentTemplate = TooltipTemplate; _content.Content = _items; if (chart.Parent != null && chart.Parent is Panel) { _container = chart.Parent as Panel; _container.Children.Add(_popup); } } public void OnDetach(XamDataChart chart) { if (_owner != chart) { return; } chart.MouseLeave -= Chart_MouseLeave; chart.MouseMove -= Chart_MouseMove; chart.SeriesCursorMouseMove -= Chart_SeriesCursorMouseMove; IsOverChart = false; _items.Clear(); _owner = null; } void Chart_MouseMove(object sender, MouseEventArgs e) { SetPopupOffsets(e.GetPosition(_owner)); IsOverChart = true; } private void SetPopupOffsets(Point point) { _popup.VerticalOffset = point.Y; _popup.HorizontalOffset = point.X + 10; } void Chart_SeriesCursorMouseMove( object sender, ChartCursorEventArgs e) { if (e.Series != null && e.Item != null) { _items.UpdateSeriesItem(e.Series, e.Item); } } void Chart_MouseLeave( object sender, MouseEventArgs e) { IsOverChart = false; } }
There are other ways to accomplish this, but this represents the simplest way, I believe.Hope this helps!-Graham
Hi,
The sample above is structured around there being seperate data items for all the points but with the same property name so that you can use a simple items control and item template in the tooltip. Since you have the data for each series in the same data item you would need to make some modifications in order to be able to display the data from the different series. I'll see if I can modify the sample for your case.
-Graham
Hello Graham,
I haven't heard anthing from yourside. Please guide me how can I accomplish my requirements.
Thanks,
M. Irfan
Thank you Graham for your comments.
I have following data item
public class ChartData : INotifyPropertyChanged { private DateTime _date; private double _value1, _value2;
public DateTime Date { get { return _date; } set { if (_date == value) return; _date = value; OnPropertyChanged("Date"); } } public double Value1 { get { return _value1; } set { if (_value1 == value) return; _value1 = value; OnPropertyChanged("Value1"); } } public double Value2 { get { return _value2; } set { if (_value2 == value) return; _value2 = value; OnPropertyChanged("Value2"); } }
Here Value1 is for first line series and Value2 is for second line series. Basically my same data item is being used for both lines series. So how can I get their values?
Hi, what does the class that you are using for your data items look like? Does it have a property called Value? If your value is in a different property make sure you update the binding that reads Item.Value to read Item.YourProperty where YourProperty is whatever property contains the value of the item.
Let me know if this helps.