These images are of same graph but on zoom in zoomout of graph and on stretch and compression of window. Can any body suggest some thing to fix the problem Thanks.
Message before inserting images:
Hi,
I am working on xamdatachart markers I am trying to display markers on a series based on data not to all dataponts. I am successfull to do so but I have identified some abnormal behavours. On zoomin,zoomout of chart and on compression and stretching window its appearing and dis apearing from the series. Please find attached screen shots for better insight of the issue:
Are those scatter line series or line series? Which axes are you using? How many data points are in each series? That behavior is strange, but we might need to have more information about your data to replicate. Can you provide a sample?
Thanks,
Graham
Hi Graham,
Thanks for replying I am attaching my wpf sample application with bugs.
There were a few things that weren't working appropriately for WPF. Here is an improved version:
<Window.Resources> <local:TestData x:Key="vm" /> </Window.Resources> <Grid x:Name="LayoutRoot" Background="White"> <igChart:XamDataChart x:Name="chart" VerticalZoomable="True" HorizontalZoomable="True" > <local:ChartBehaviors.ChartPoints> <local:ChartPointsBehavior> <local:ChartPointsBehavior.PointTemplate> <DataTemplate> <Grid > <Grid x:Name="container" Width="6" Height="6"/> <!--<ContentPresenter Margin="6,6,6,6" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> </ContentPresenter>--> <!--<Popup IsOpen="True" DataContext="{Binding}" AllowsTransparency="True" PlacementTarget="{Binding ElementName=container}" Placement="Relative">--> <Canvas Width="0" Height="0"> <Path Data="M 1,1 L 17,17" Stroke="Black" StrokeThickness=".5" /> <Border Margin="12,12" Background="White" CornerRadius="5" BorderThickness=".5" BorderBrush="Black" > <TextBlock Margin="3" Text="{Binding Data.Label}" /> </Border> </Canvas> <!--</Popup>--> </Grid> </DataTemplate> </local:ChartPointsBehavior.PointTemplate> <local:ChartPointsBehavior.Points> <local:PointInfo X="1" Y="2" DataIndex="1"> </local:PointInfo> <local:PointInfo X="3" Y="4" DataIndex="3"> </local:PointInfo> </local:ChartPointsBehavior.Points> </local:ChartPointsBehavior> </local:ChartBehaviors.ChartPoints> <igChart:XamDataChart.Axes> <igChart:CategoryXAxis x:Name="xAxis" ItemsSource="{StaticResource vm}" Label="{}{Label}" /> <igChart:NumericYAxis x:Name="yAxis" /> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:LineSeries x:Name="line" MarkerType="Triangle" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ValueMemberPath="Value" ItemsSource="{StaticResource vm}"/> </igChart:XamDataChart.Series> </igChart:XamDataChart> </Grid>
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class TestData : ObservableCollection<TestDataItem> { public TestData() { Add(new TestDataItem() { Label = "1", Value = 1 }); Add(new TestDataItem() { Label = "2", Value = 2 }); Add(new TestDataItem() { Label = "3", Value = 3 }); Add(new TestDataItem() { Label = "4", Value = 4 }); Add(new TestDataItem() { Label = "5", Value = 5 }); Add(new TestDataItem() { Label = "6", Value = 6 }); Add(new TestDataItem() { Label = "7", Value = 7 }); } } public class TestDataItem { public string Label { get; set; } public double Value { get; set; } } public class ChartBehaviors : DependencyObject { public static readonly DependencyProperty ChartPointsProperty = DependencyProperty.RegisterAttached("ChartPoints", typeof(ChartPointsBehavior), typeof(ChartBehaviors), new PropertyMetadata(null, (o, e) => CursorTooltipChanged( o as XamDataChart, e.OldValue as ChartPointsBehavior, e.NewValue as ChartPointsBehavior))); public static ChartPointsBehavior GetChartPoints( DependencyObject target) { return target.GetValue(ChartPointsProperty) as ChartPointsBehavior; } public static void SetChartPoints( DependencyObject target, ChartPointsBehavior behavior) { target.SetValue(ChartPointsProperty, behavior); } private static void CursorTooltipChanged( XamDataChart chart, ChartPointsBehavior oldValue, ChartPointsBehavior newValue) { if (chart == null) { return; } if (oldValue != null) { oldValue.OnDetach(chart); } if (newValue != null) { newValue.OnAttach(chart); } } } public class PointInfo : FrameworkElement { public PointInfo() { _id = Guid.NewGuid(); X = double.NaN; Y = double.NaN; } private PointInfo(Guid id) { _id = id; X = double.NaN; Y = double.NaN; } private Guid _id; public Guid Id { get { return _id; } private set { _id = value; } } public double X { get; set; } public double Y { get; set; } public string Label { get; set; } public Brush Fill { get; set; } public DataTemplate PointTemplate { get; set; } public static readonly DependencyProperty DataProperty = DependencyProperty.Register( "Data", typeof(object), typeof(PointInfo), new PropertyMetadata(null)); public object Data { get { return GetValue(DataProperty); } set { SetValue(DataProperty, value); } } public static readonly DependencyProperty DataIndexProperty = DependencyProperty.Register( "DataIndex", typeof(int), typeof(PointInfo), new PropertyMetadata(-1)); public int DataIndex { get { return (int)GetValue(DataIndexProperty); } set { SetValue(DataIndexProperty, value); } } public PointInfo Clone() { PointInfo newPointInfo = new PointInfo(_id); newPointInfo.X = X; newPointInfo.Y = Y; newPointInfo.Label = Label; newPointInfo.PointTemplate = PointTemplate; newPointInfo.Fill = Fill; newPointInfo.DataIndex = DataIndex; BindingOperations.SetBinding( newPointInfo, PointInfo.DataProperty, new Binding("Data") { Source = this }); return newPointInfo; } } public class PointInfoCollection : ObservableCollection<PointInfo> { } public class ChartPointsBehavior : DependencyObject { public ChartPointsBehavior() { Points = new PointInfoCollection(); } public static readonly DependencyProperty StripsProperty = DependencyProperty.Register("Points", typeof(PointInfoCollection), typeof(ChartPointsBehavior), new PropertyMetadata(null, (o, e) => (o as ChartPointsBehavior) .OnPointsChanged( e.OldValue as PointInfoCollection, e.NewValue as PointInfoCollection))); public PointInfoCollection Points { get { return (PointInfoCollection)GetValue(StripsProperty); } set { SetValue(StripsProperty, value); } } public DataTemplate PointTemplate { get; set; } private void OnPointsChanged( PointInfoCollection oldValue, PointInfoCollection newValue) { if (oldValue != null) { oldValue.CollectionChanged -= Points_CollectionChanged; } if (newValue != null) { newValue.CollectionChanged += Points_CollectionChanged; } RefreshPoints(); } void Points_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e) { RefreshPoints(); } private XamDataChart _owner = null; public void OnAttach(XamDataChart chart) { if (_owner != null) { OnDetach(_owner); } _owner = chart; _owner.WindowRectChanged += Owner_WindowRectChanged; _owner.SizeChanged += Owner_SizeChanged; _owner.Axes.CollectionChanged += Axes_CollectionChanged; _owner.Axes.CollectionResetting += Axes_CollectionResetting; RefreshPoints(); } void Owner_SizeChanged(object sender, SizeChangedEventArgs e) { RefreshPoints(); } void Axes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (Axis axis in e.OldItems) { axis.SizeChanged -= Axis_SizeChanged; } } if (e.NewItems != null) { foreach (Axis axis in e.NewItems) { axis.SizeChanged += Axis_SizeChanged; } } RefreshPoints(); } void Axis_SizeChanged(object sender, SizeChangedEventArgs e) { RefreshPoints(); } void Axes_CollectionResetting(object sender, EventArgs e) { foreach (Axis axis in _owner.Axes) { axis.SizeChanged -= Axis_SizeChanged; } RefreshPoints(); } void Owner_WindowRectChanged(object sender, Infragistics.RectChangedEventArgs e) { RefreshPoints(); } private void GetAxes( out Axis xAxis, out Axis yAxis) { if (_owner == null) { xAxis = null; yAxis = null; return; } xAxis = (from axis in _owner.Axes where axis is NumericXAxis || axis is CategoryXAxis || axis is CategoryDateTimeXAxis select axis).FirstOrDefault(); yAxis = (from axis in _owner.Axes where axis is NumericYAxis select axis).FirstOrDefault(); } private Series GetSeries() { if (_owner == null) { return null; } return _owner.Series.FirstOrDefault(); } private void ClearExisting() { var series = GetSeries(); if (series == null) { return; } if (series.RootCanvas == null) { return; } var existing = from child in series.RootCanvas.Children .OfType<ContentControl>() where child.Content != null && child.Content is PointInfo select child; existing.ToList().ForEach( (ele) => series.RootCanvas.Children.Remove(ele)); } private void RefreshPoints() { Axis xAxis; Axis yAxis; GetAxes(out xAxis, out yAxis); if (xAxis == null || yAxis == null || xAxis.RootCanvas == null) { return; } ClearExisting(); Rect viewport = GetViewportRect(xAxis); foreach (PointInfo info in Points) { PointInfo toAdd = info.Clone(); if (double.IsNaN(toAdd.X)) { toAdd.X = viewport.Left; } else { toAdd.X = xAxis.GetScaledValue( toAdd.X, _owner.WindowRect, viewport); } if (double.IsNaN(toAdd.Y)) { toAdd.Y = viewport.Top; } else { toAdd.Y = yAxis.GetScaledValue( toAdd.Y, _owner.WindowRect, viewport); } if (toAdd.PointTemplate == null) { toAdd.PointTemplate = this.PointTemplate; } if (toAdd.PointTemplate != null && !double.IsNaN(toAdd.Y) && !double.IsInfinity(toAdd.Y) && !double.IsNaN(toAdd.X) && !double.IsInfinity(toAdd.X)) { var series = GetSeries(); if (series == null) { continue; } var pointControl = new ContentControl(); Canvas.SetZIndex(pointControl, 2000); if (toAdd.DataIndex >= 0) { toAdd.SetBinding( PointInfo.DataProperty, new Binding( "ItemsSource[" + toAdd.DataIndex + "]") { Source = series }); } pointControl.ContentTemplate = toAdd.PointTemplate; pointControl.Content = toAdd; series.RootCanvas.Children.Add(pointControl); pointControl.Measure( new Size( double.PositiveInfinity, double.PositiveInfinity)); Canvas.SetLeft(pointControl, toAdd.X - (pointControl.DesiredSize.Width / 2.0)); Canvas.SetTop(pointControl, toAdd.Y - (pointControl.DesiredSize.Height / 2.0)); } } } private Rect GetViewportRect( Axis axis) { double top = 0; double bottom = axis.ActualHeight; double left = 0; double right = axis.ActualWidth; double width = right - left; double height = bottom - top; if (width > 0.0 && height > 0.0) { return new Rect(left, top, width, height); } return Rect.Empty; } public void OnDetach(XamDataChart chart) { if (_owner != chart) { return; } _owner.WindowRectChanged -= Owner_WindowRectChanged; _owner.SizeChanged -= Owner_SizeChanged; _owner.Axes.CollectionChanged -= Axes_CollectionChanged; _owner.Axes.CollectionResetting -= Axes_CollectionResetting; Axis xAxis; Axis yAxis; GetAxes(out xAxis, out yAxis); if (xAxis == null || yAxis == null) { return; } ClearExisting(); _owner = null; } }
Hope this helps!
-Graham
Thanks for the solution its working fine but only problem with this solution is its points on which annotation needs to deffine are statice and I have tried to make it dynamic but I am not success full in it. Moreover position of annotation which is based on X and Y value in PointInfo how can I make them dynamic as well, I tried to bind my maker point values with it but its not working. Can you please suggest the solution. Moreover did you guys find out any solid solution for this problem.
Thanks.
Modifying the contents of the Points collection in the attached property should update the annotations dynamically. So, for example, if you wanted to add an additional annotation programatically, you could do something like this:
ChartBehaviors.GetChartPoints(chart1).Points.Add(new PointInfo() { X = 4, Y = 10, DataIndex = 3 });
But if you wanted to set X and Y via a binding, you would have to make PointInfo a Dependency object and change X and Y to be dependency properties and have PointInfo implement INotifyPropertyChanged. Then your ChartPointsBehavior would have to register and unregister to the property changed event for these point info's to know when the visuals need to be refreshed based on the X and Y values changing. This increases the complexity of this sample somewhat, so is left as an excercise to the reader, but is not that difficult to implement. Let me know if you need any further advice.
I have tried your proposed solution but its not working for me. May be I am missing some thing please find attached my sample application attached and please suggest some solution.
Thanks
Here's one way how you might make the points more dynamic with some bindings:
<Window.Resources> <local:TestData x:Key="vm" /> </Window.Resources> <Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions > <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <igChart:XamDataChart x:Name="chart" VerticalZoomable="True" HorizontalZoomable="True" > <local:ChartBehaviors.ChartPoints> <local:ChartPointsBehavior> <local:ChartPointsBehavior.PointTemplate> <DataTemplate> <Grid > <Grid x:Name="container" Width="6" Height="6"/> <Canvas Width="0" Height="0"> <Path Data="M 1,1 L 17,17" Stroke="Black" StrokeThickness=".5" /> <Border Margin="12,12" Background="White" CornerRadius="5" BorderThickness=".5" BorderBrush="Black" > <TextBlock Margin="3" Text="{Binding Data.Label}" /> </Border> </Canvas> </Grid> </DataTemplate> </local:ChartPointsBehavior.PointTemplate> <local:ChartPointsBehavior.Points> <local:PointInfo X="1" Y="{Binding Source={StaticResource vm}, Path=[1].Value}" DataIndex="1"> </local:PointInfo> <local:PointInfo X="3" Y="{Binding Source={StaticResource vm}, Path=[3].Value}" DataIndex="3"> </local:PointInfo> </local:ChartPointsBehavior.Points> </local:ChartPointsBehavior> </local:ChartBehaviors.ChartPoints> <igChart:XamDataChart.Axes> <igChart:CategoryXAxis x:Name="xAxis" ItemsSource="{StaticResource vm}" Label="{}{Label}" /> <igChart:NumericYAxis x:Name="yAxis" /> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:LineSeries x:Name="line" MarkerType="Triangle" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ValueMemberPath="Value" ItemsSource="{StaticResource vm}"/> </igChart:XamDataChart.Series> </igChart:XamDataChart> <Button Grid.Row="1" x:Name="click" Content="Click" Click="click_Click"/> </Grid>
Code behind:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void click_Click(object sender, RoutedEventArgs e) { (Resources["vm"] as TestData)[1].Value++; } } public class TestData : ObservableCollection<TestDataItem> { public TestData() { Add(new TestDataItem() { Label = "1", Value = 1 }); Add(new TestDataItem() { Label = "2", Value = 2 }); Add(new TestDataItem() { Label = "3", Value = 3 }); Add(new TestDataItem() { Label = "4", Value = 4 }); Add(new TestDataItem() { Label = "5", Value = 5 }); Add(new TestDataItem() { Label = "6", Value = 6 }); Add(new TestDataItem() { Label = "7", Value = 7 }); } } public class TestDataItem : INotifyPropertyChanged { private string _label; public string Label { get { return _label; } set { _label = value; RaisePropertyChanged("Label"); } } private double _value; public double Value { get { return _value; } set { _value = value; RaisePropertyChanged("Value"); } } public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged( this, new PropertyChangedEventArgs(propertyName)); } } } public class ChartBehaviors : DependencyObject { public static readonly DependencyProperty ChartPointsProperty = DependencyProperty.RegisterAttached("ChartPoints", typeof(ChartPointsBehavior), typeof(ChartBehaviors), new PropertyMetadata(null, (o, e) => CursorTooltipChanged( o as XamDataChart, e.OldValue as ChartPointsBehavior, e.NewValue as ChartPointsBehavior))); public static ChartPointsBehavior GetChartPoints( DependencyObject target) { return target.GetValue(ChartPointsProperty) as ChartPointsBehavior; } public static void SetChartPoints( DependencyObject target, ChartPointsBehavior behavior) { target.SetValue(ChartPointsProperty, behavior); } private static void CursorTooltipChanged( XamDataChart chart, ChartPointsBehavior oldValue, ChartPointsBehavior newValue) { if (chart == null) { return; } if (oldValue != null) { oldValue.OnDetach(chart); } if (newValue != null) { newValue.OnAttach(chart); } } } public class PointInfo : FrameworkElement { public PointInfo() { _id = Guid.NewGuid(); X = double.NaN; Y = double.NaN; } private PointInfo(Guid id) { _id = id; X = double.NaN; Y = double.NaN; } private Guid _id; public Guid Id { get { return _id; } private set { _id = value; } } public static readonly DependencyProperty XProperty = DependencyProperty.Register( "X", typeof(double), typeof(PointInfo), new PropertyMetadata(0.0, (o, e) => (o as PointInfo).OnPropertyChanged( "X", e.OldValue, e.NewValue))); private void OnPropertyChanged(string propertyName, object oldValue, object newValue) { if (Owner != null) { Owner.SignalNeedsRefresh(); } } public double X { get { return (double)GetValue(XProperty); } set { SetValue(XProperty, value); } } public static readonly DependencyProperty YProperty = DependencyProperty.Register( "Y", typeof(double), typeof(PointInfo), new PropertyMetadata(0.0, (o, e) => (o as PointInfo).OnPropertyChanged( "Y", e.OldValue, e.NewValue))); public double Y { get { return (double)GetValue(YProperty); } set { SetValue(YProperty, value); } } public static readonly DependencyProperty LabelProperty = DependencyProperty.Register( "Label", typeof(string), typeof(PointInfo), new PropertyMetadata("", (o, e) => (o as PointInfo).OnPropertyChanged( "Label", e.OldValue, e.NewValue))); public string Label { get { return (string)GetValue(LabelProperty); } set { SetValue(LabelProperty, value); } } public Brush Fill { get; set; } public DataTemplate PointTemplate { get; set; } public static readonly DependencyProperty DataProperty = DependencyProperty.Register( "Data", typeof(object), typeof(PointInfo), new PropertyMetadata(null, (o, e) => (o as PointInfo).OnPropertyChanged( "Data", e.OldValue, e.NewValue))); public object Data { get { return GetValue(DataProperty); } set { SetValue(DataProperty, value); } } public static readonly DependencyProperty DataIndexProperty = DependencyProperty.Register( "DataIndex", typeof(int), typeof(PointInfo), new PropertyMetadata(-1, (o, e) => (o as PointInfo).OnPropertyChanged( "DataIndex", e.OldValue, e.NewValue))); public int DataIndex { get { return (int)GetValue(DataIndexProperty); } set { SetValue(DataIndexProperty, value); } } public PointInfo Clone() { PointInfo newPointInfo = new PointInfo(_id); newPointInfo.X = X; newPointInfo.Y = Y; newPointInfo.Label = Label; newPointInfo.PointTemplate = PointTemplate; newPointInfo.Fill = Fill; newPointInfo.DataIndex = DataIndex; BindingOperations.SetBinding( newPointInfo, PointInfo.DataProperty, new Binding("Data") { Source = this }); return newPointInfo; } public PointInfoCollection Owner { get; set; } } public class PointInfoCollection : ObservableCollection<PointInfo> { protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { base.OnCollectionChanged(e); if (e.OldItems != null) { foreach (var item in e.OldItems.OfType<PointInfo>()) { item.Owner = null; } } if (e.NewItems != null) { foreach (var item in e.NewItems.OfType<PointInfo>()) { item.Owner = this; } } } internal void SignalNeedsRefresh() { if (NeedsRefresh != null) { NeedsRefresh(this); } } public delegate void NeedsRefreshEventHandler(object o); public event NeedsRefreshEventHandler NeedsRefresh; } public class ChartPointsBehavior : DependencyObject { public ChartPointsBehavior() { Points = new PointInfoCollection(); } public static readonly DependencyProperty StripsProperty = DependencyProperty.Register("Points", typeof(PointInfoCollection), typeof(ChartPointsBehavior), new PropertyMetadata(null, (o, e) => (o as ChartPointsBehavior) .OnPointsChanged( e.OldValue as PointInfoCollection, e.NewValue as PointInfoCollection))); public PointInfoCollection Points { get { return (PointInfoCollection)GetValue(StripsProperty); } set { SetValue(StripsProperty, value); } } public DataTemplate PointTemplate { get; set; } private void OnPointsChanged( PointInfoCollection oldValue, PointInfoCollection newValue) { if (oldValue != null) { oldValue.CollectionChanged -= Points_CollectionChanged; oldValue.NeedsRefresh -= NewValue_NeedsRefresh; } if (newValue != null) { newValue.CollectionChanged += Points_CollectionChanged; newValue.NeedsRefresh += NewValue_NeedsRefresh; } RefreshPoints(); } void NewValue_NeedsRefresh(object o) { RefreshPoints(); } void Points_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e) { RefreshPoints(); } private XamDataChart _owner = null; public void OnAttach(XamDataChart chart) { if (_owner != null) { OnDetach(_owner); } _owner = chart; _owner.WindowRectChanged += Owner_WindowRectChanged; _owner.SizeChanged += Owner_SizeChanged; _owner.Axes.CollectionChanged += Axes_CollectionChanged; _owner.Axes.CollectionResetting += Axes_CollectionResetting; RefreshPoints(); } void Owner_SizeChanged(object sender, SizeChangedEventArgs e) { RefreshPoints(); } void Axes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (Axis axis in e.OldItems) { axis.SizeChanged -= Axis_SizeChanged; } } if (e.NewItems != null) { foreach (Axis axis in e.NewItems) { axis.SizeChanged += Axis_SizeChanged; } } RefreshPoints(); } void Axis_SizeChanged(object sender, SizeChangedEventArgs e) { RefreshPoints(); } void Axes_CollectionResetting(object sender, EventArgs e) { foreach (Axis axis in _owner.Axes) { axis.SizeChanged -= Axis_SizeChanged; } RefreshPoints(); } void Owner_WindowRectChanged(object sender, Infragistics.RectChangedEventArgs e) { RefreshPoints(); } private void GetAxes( out Axis xAxis, out Axis yAxis) { if (_owner == null) { xAxis = null; yAxis = null; return; } xAxis = (from axis in _owner.Axes where axis is NumericXAxis || axis is CategoryXAxis || axis is CategoryDateTimeXAxis select axis).FirstOrDefault(); yAxis = (from axis in _owner.Axes where axis is NumericYAxis select axis).FirstOrDefault(); } private Series GetSeries() { if (_owner == null) { return null; } return _owner.Series.FirstOrDefault(); } private void ClearExisting() { var series = GetSeries(); if (series == null) { return; } if (series.RootCanvas == null) { return; } var existing = from child in series.RootCanvas.Children .OfType<ContentControl>() where child.Content != null && child.Content is PointInfo select child; existing.ToList().ForEach( (ele) => series.RootCanvas.Children.Remove(ele)); } private void RefreshPoints() { Axis xAxis; Axis yAxis; GetAxes(out xAxis, out yAxis); if (xAxis == null || yAxis == null || xAxis.RootCanvas == null) { return; } ClearExisting(); Rect viewport = GetViewportRect(xAxis); foreach (PointInfo info in Points) { PointInfo toAdd = info.Clone(); if (double.IsNaN(toAdd.X)) { toAdd.X = viewport.Left; } else { toAdd.X = xAxis.GetScaledValue( toAdd.X, _owner.WindowRect, viewport); } if (double.IsNaN(toAdd.Y)) { toAdd.Y = viewport.Top; } else { toAdd.Y = yAxis.GetScaledValue( toAdd.Y, _owner.WindowRect, viewport); } if (toAdd.PointTemplate == null) { toAdd.PointTemplate = this.PointTemplate; } if (toAdd.PointTemplate != null && !double.IsNaN(toAdd.Y) && !double.IsInfinity(toAdd.Y) && !double.IsNaN(toAdd.X) && !double.IsInfinity(toAdd.X)) { var series = GetSeries(); if (series == null) { continue; } var pointControl = new ContentControl(); Canvas.SetZIndex(pointControl, 2000); if (toAdd.DataIndex >= 0) { toAdd.SetBinding( PointInfo.DataProperty, new Binding( "ItemsSource[" + toAdd.DataIndex + "]") { Source = series }); } pointControl.ContentTemplate = toAdd.PointTemplate; pointControl.Content = toAdd; series.RootCanvas.Children.Add(pointControl); pointControl.Measure( new Size( double.PositiveInfinity, double.PositiveInfinity)); Canvas.SetLeft(pointControl, toAdd.X - (pointControl.DesiredSize.Width / 2.0)); Canvas.SetTop(pointControl, toAdd.Y - (pointControl.DesiredSize.Height / 2.0)); } } } private Rect GetViewportRect( Axis axis) { double top = 0; double bottom = axis.ActualHeight; double left = 0; double right = axis.ActualWidth; double width = right - left; double height = bottom - top; if (width > 0.0 && height > 0.0) { return new Rect(left, top, width, height); } return Rect.Empty; } public void OnDetach(XamDataChart chart) { if (_owner != chart) { return; } _owner.WindowRectChanged -= Owner_WindowRectChanged; _owner.SizeChanged -= Owner_SizeChanged; _owner.Axes.CollectionChanged -= Axes_CollectionChanged; _owner.Axes.CollectionResetting -= Axes_CollectionResetting; Axis xAxis; Axis yAxis; GetAxes(out xAxis, out yAxis); if (xAxis == null || yAxis == null) { return; } ClearExisting(); _owner = null; } }