Hi,
I try to display several ScatterLineSeries in one xamDadaChart. Since they are unknown in count at designtime, I have to add them in code behind.
Previous first steps were made in LineSeries. Therein I managed to add a ToolTip in Code behind as well displaying Value and TimeStamp while hovering over the chart.
Now I was hoping that I would be able to simply copy and paste that snippet and it would work - I know, a little naive for a developer (I hope that caused a smile). You might have guessed it already, it did NOT work.
The following snippet compiles and runs. Unfortunately, it does not show up in the chart:
ScatterLineSeries series = new ScatterLineSeries();//some more code to initialize the scatter series//end of the initialisationStackPanel sp = new StackPanel(){ Orientation = System.Windows.Controls.Orientation.Vertical};var txtbl = new TextBlock();txtbl.SetBinding(TextBlock.TextProperty, new Binding("Series.Title"));sp.Children.Add(txtbl);txtbl = new TextBlock();txtbl.SetBinding(TextBlock.TextProperty, new Binding("Item.Value"));sp.Children.Add(txtbl);txtbl = new TextBlock();txtbl.SetBinding(TextBlock.TextProperty, new Binding("Item.DateString"));sp.Children.Add(txtbl);series.ToolTip = sp;
Hi, do you see any binding errors in the output window when you run this? What do your items look like?
Hi Graham,
No, there are no errors at all in my Output. A single Enumerator item looks like this:
public class DataElement{ private String _DateString = ""; private Double _DateValue = 0; private Double _Data = 0; public DataElement(String dateString, Double dateValue, Double data) { _DateString = dateString; _DateValue = dateValue; _Data = data; } public String DateString { get { return _DateString; } set { _DateString = value; } }
public Double DateValue { get { return _DateValue; } set { _DateValue = value; } } public DateTime DateValueDt { get { return DateTime.FromOADate(_DateValue); } } public Double Data { get { return _Data; } set { _Data = value; } } public Object Value { get { return _Data; } } public override string ToString() { return _DateString + ":" + _DateValue.ToString() + ":" + _Data.ToString(); }}
As you can see, this is a very simple container class. It worked amazingly nice in a sample with the LineSeries together with a CategoryXAxis. When I switched to ScatterLineSeries and NumericXAxis however, the ToolTip stopped working. If I can provide any further information, please ask. I will try to post them as soon as possible.
Thank you very much for your reply and your attempts to help.
Enrico
It has just occurred to me. Are you mousing over the line and the tooltip isn't showing up, or tha markers?
-Graham
Yes, exactly that ...
Did I miss something?
I will answer myself, for the first problem, we can erase both lines.
The second one, I have performed everything in the code behind and it works.
And my third new issue, how to template the popup window to be of the same type of the normal tooltip of a normal line serie or the legend?
Thank you
Thank you for the post.
I have copy pasted the code in my silverlight app, that but I am getting some issues, it can't resolve the symbols placement and placementTarget.
Also, I am trying to develop a MVVM pattern and I can not give a class from my viewModel in my view, so I can't create a class to fill the tooltip. Any other Idea? thank you
Here's how you could make the tooltip show up whenever you are over a scatterlineseries:
<Window.Resources> <local:TestData x:Key="data" /> </Window.Resources> <Grid> <igChart:XamDataChart x:Name="theChart" Loaded="theChart_Loaded"> <igChart:XamDataChart.Axes> <igChart:NumericXAxis x:Name="xAxis" /> <igChart:NumericYAxis x:Name="yAxis" /> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:ScatterLineSeries x:Name="scatter" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" XMemberPath="XValue" YMemberPath="YValue" ItemsSource="{StaticResource data}" Thickness="3" > </igChart:ScatterLineSeries> </igChart:XamDataChart.Series> </igChart:XamDataChart> <Popup x:Name="thePopup" IsOpen="False"> <Border Background="White" BorderBrush="Gray" BorderThickness="1" Padding="4"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding XValue}" /> <TextBlock Text=", " /> <TextBlock Text="{Binding YValue}" /> </StackPanel> </Border> </Popup> </Grid>
with code behind:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private ScatterTooltipManager<TestDataItem> _manager; private void theChart_Loaded(object sender, RoutedEventArgs e) { _manager = new ScatterTooltipManager<TestDataItem>( theChart, theChart.Series[0] as ScatterBase, (i) => i.XValue, (i) => i.YValue, thePopup); } } public class ScatterTooltipManager<T> { private ScatterBase _scatterSeries = null; private Func<T, double> _xMapping = null; private Func<T, double> _yMapping = null; private Popup _tooltipContainer = null; public ScatterTooltipManager( XamDataChart chart, ScatterBase scatterSeries, Func<T, double> xMapping, Func<T, double> yMapping, Popup tooltipContainer) { chart.SeriesMouseMove += new DataChartMouseEventHandler(chart_SeriesMouseMove); chart.SeriesMouseLeave += new DataChartMouseEventHandler(chart_SeriesMouseLeave); _scatterSeries = scatterSeries; _xMapping = xMapping; _yMapping = yMapping; _tooltipContainer = tooltipContainer; } void chart_SeriesMouseLeave(object sender, ChartMouseEventArgs e) { if (e.Series == _scatterSeries) { _tooltipContainer.IsOpen = false; } } void chart_SeriesMouseMove(object sender, ChartMouseEventArgs e) { if (e.Series != _scatterSeries) { return; } var item = FindClosestItem(e); var pos = e.GetPosition(_scatterSeries); _tooltipContainer.Placement = PlacementMode.Relative; _tooltipContainer.PlacementTarget = _scatterSeries; _tooltipContainer.HorizontalOffset = pos.X + 10; _tooltipContainer.VerticalOffset = pos.Y + 10; _tooltipContainer.DataContext = item; _tooltipContainer.IsOpen = true; } private object FindClosestItem(ChartMouseEventArgs e) { var pos = e.GetPosition(_scatterSeries); var viewport = new Rect(0, 0, _scatterSeries.ActualWidth, _scatterSeries.ActualHeight); var x = _scatterSeries.XAxis.GetUnscaledValue( pos.X, _scatterSeries.Chart.WindowRect, viewport); var y = _scatterSeries.YAxis.GetUnscaledValue( pos.Y, _scatterSeries.Chart.WindowRect, viewport); var minDistance = double.MaxValue; T minItem = default(T); foreach (var item in _scatterSeries.ItemsSource.OfType<T>()) { var itemX = _xMapping(item); var itemY = _yMapping(item); var dist = GetDistance(itemX, itemY, x, y); if (dist < minDistance) { minDistance = dist; minItem = item; } } return minItem; } private double GetDistance(double itemX, double itemY, double x, double y) { return Math.Sqrt(Math.Pow(itemX - x, 2) + Math.Pow(itemY - y, 2)); } } public class TestDataItem { public double XValue { get; set; } public double YValue { get; set; } } public class TestData : ObservableCollection<TestDataItem> { public TestData() { Add(new TestDataItem() { XValue = 0, YValue = 0 }); Add(new TestDataItem() { XValue = 1, YValue = 1 }); Add(new TestDataItem() { XValue = 2, YValue = 2 }); Add(new TestDataItem() { XValue = 3, YValue = 3 }); Add(new TestDataItem() { XValue = 4, YValue = 4 }); Add(new TestDataItem() { XValue = 5, YValue = 5 }); } }
Hope this helps!-Graham
I enabled the the markers for the series and - voila - there is a ToolTip. Thank you very much for your help so far.
I look forward to read more about it. Maybe i can enable/disable this behaviour depending on the ammount of data or let the user pick his/her poison.
Anyways, keep up the good work!
Currently the default behavior for the scatter series it to only show the tooltips when you are over a marker, as it can be somewhat expensive to determine which point you are closest too, if you have a lot of points and are over a connecting line.
You should be able to do something in application code to get the tooltips to function over the line though, I'll get back to you.