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.
Hi,
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
Hi Graham,
Thanks for replying I am attaching my wpf sample application with bugs.
Have you had any trouble running the above in WPF? It should run in Silverlight or WPF and if there are changes required they would be relatively minor. The above extends a user control so you could either paste the code into a user control, or change any references to user control to window, and you could name the control MainWindow rather than MainPage.
The above presented solution is in silverlight I think. Actually I am working on WPF can you please provide me a wpf version as well.
Thanks.
Here is an sample of how to approach point annotations that you might find useful:
The Xaml:
<UserControl.Resources> <local:TestData x:Key="vm" /> </UserControl.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> <ContentPresenter Margin="6,6,6,6" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> </ContentPresenter> <Popup IsOpen="True" DataContext="{Binding}"> <Grid> <Path Data="M 6,6 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.Item.Label}" /> </Border> </Grid> </Popup> </Grid> </DataTemplate> </local:ChartPointsBehavior.PointTemplate> <local:ChartPointsBehavior.Points> <local:PointInfo X="1" Y="2"> <local:PointInfo.Data> <igChart:DataContext Series="{Binding ElementName=line}" Item="{Binding ElementName=line, Path=ItemsSource[1]}"/> </local:PointInfo.Data> </local:PointInfo> <local:PointInfo X="3" Y="4"> <local:PointInfo.Data> <igChart:DataContext Series="{Binding ElementName=line}" Item="{Binding ElementName=line, Path=ItemsSource[3]}"/> </local:PointInfo.Data> </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>
And the code behind:
public partial class MainPage : UserControl { public MainPage() { 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 : DependencyObject { 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 PointInfo Clone() { PointInfo newPointInfo = new PointInfo(_id); newPointInfo.X = X; newPointInfo.Y = Y; newPointInfo.Label = Label; newPointInfo.PointTemplate = PointTemplate; newPointInfo.Fill = Fill; 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 where child is ContentControl && (child as ContentControl).Content != null && (child as ContentControl).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); 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; } }
Let me know if that's what you are going for, it produces a result that looks like this: