Adding a TextBlock (or Label) to the End of a DataSeries DataPoint for a DataVisualizationChart

I am creating a User Control component of type DataVisualization.Chart. Currently, it accepts 4 ranges (1 minimum value of the received value and 1 maximum, as well as 1 minimum value of the warning range and 1 maximum value of the warning range). So far, so good. It is working. But I need to add a TextBlock (or a shortcut, or TextBox, whatever) at the end of the LineSeries.

This is my actual LineSeries:

Chart without label

Now I need to do something like this:

Chart with label

Even if the result is not the same, I need to put a label or text block at the end of each LineDataPoint.

Change 1:

This is how my list of items is generated:

/// <summary> /// Generate ItemsSource to use with chart component /// </summary> /// <returns>A observable collection items of ChartItems type</returns> public ObservableCollection<ChartItems> GenerateActualValues() { var itemsSource = ItemsSource as IEnumerable; if (itemsSource.IsNull()) return null; // Get all values from ItemsSource to set Axis Y of Chart List<Double> listAxisY = new List<Double>(); ObservableCollection<ChartItems> chartItems = new ObservableCollection<ChartItems>(); foreach (ChartItems itemSource in itemsSource) { listAxisY.Add(itemSource.ValueY); chartItems.Add(new ChartItems { Name = itemSource.Name, ValueY = itemSource.ValueY, ValueXDouble = itemSource.ValueXDouble, ValueXDateTime = itemSource.ValueXDateTime, Color = itemSource.Color }); } // Set minimum and maximum axis Y if automatic if (AutomaticAxisY) { Double? maxValue; Double? minValue; if (listAxisY.Count > 0) { if (GetMaxLimitValue1(this) > listAxisY.Max()) maxValue = GetMaxLimitValue1(this); else maxValue = listAxisY.Max(); if (GetMinLimitValue1(this) < listAxisY.Min()) minValue = GetMinLimitValue1(this); else minValue = listAxisY.Min(); } else { maxValue = GetMaxLimitValue1(this); minValue = GetMinLimitValue1(this); } Double? increment = (maxValue - minValue) * 0.05; MaximumAxisY = (maxValue + increment).ConvertNullDoubleToDouble(); MinimumAxisY = (minValue - increment).ConvertNullDoubleToDouble(); if (MaximumAxisY == MinimumAxisY) { MaximumAxisY += 1; MinimumAxisY -= 1; } } return chartItems; } 

Basically, it generates a new ItemSource for use in my schedule. Now, to generate these additional lines:

 /// <summary> /// Generate a ItemsSource using param option informed /// </summary> /// <param name="option">Min1, Max1, Min2, Max2 or Target Value</param> /// <returns>Observable Collection of ChartItems</returns> public ObservableCollection<ChartItems> GenerateLimitValues(String option) { var itemsSource = ItemsSource as IEnumerable; if (itemsSource.IsNull()) return null; Double? valueY = 0.0; ObservableCollection<ChartItems> chartItems = new ObservableCollection<ChartItems>(); switch (option) { case "Min1": valueY = GetMinLimitValue1(this); break; case "Max1": valueY = GetMaxLimitValue1(this); break; case "Target": valueY = GetTargetValue(this); break; case "Min2": valueY = GetMinLimitValue2(this); break; case "Max2": valueY = GetMaxLimitValue2(this); break; } foreach (ChartItems itemSource in itemsSource) chartItems.Add(new ChartItems { Name = itemSource.Name, ValueY = valueY.ConvertNullDoubleToDouble(), ValueXDouble = itemSource.ValueXDouble, ValueXDateTime = itemSource.ValueXDateTime }); return chartItems; } 

Now that all things work in my diagram:

 /// <summary> /// Generates series with values for chart /// </summary> public void RenderizeChart() { while (this.chartView.Series.Count() - 1 >= 0) this.chartView.Series.Remove(this.chartView.Series[0]); DataPointSeries lineSeriesActualValue = null; DataPointSeries lineSeriesMaxValue1 = null; DataPointSeries lineSeriesMinValue1 = null; DataPointSeries lineSeriesMaxValue2 = null; DataPointSeries lineSeriesMinValue2 = null; DataPointSeries lineSeriesTarget = null; if (!ChartTypeSelectedItem.IsNull()) switch ((ChartTypes)ChartTypeSelectedItem) { case ChartTypes.Bar: this.chartView.Series.Add(new BarSeries()); lineSeriesActualValue = this.chartView.Series[0] as BarSeries; break; case ChartTypes.Columns: this.chartView.Series.Add(new ColumnSeries()); lineSeriesActualValue = this.chartView.Series[0] as ColumnSeries; lineSeriesActualValue.DataPointStyle = (Style)this.Resources["ColumnDataPointStyle"]; break; case ChartTypes.Pie: this.chartView.Series.Add(new PieSeries()); lineSeriesActualValue = this.chartView.Series[0] as PieSeries; break; case ChartTypes.Lines: this.chartView.Series.Add(new LineSeries()); lineSeriesActualValue = this.chartView.Series[0] as LineSeries; lineSeriesActualValue.Style = (Style)this.Resources["LineSeriesStyle"]; if (!ShowPoints) { // Brief explanation: if user wants to hide Data Points, it necessary to get all Setters on // LineDataPointStyle inside xaml, clear previous style and add new Setter. // Otherwise, it will not work, will deny changes because its sealed. Style style = (Style)this.Resources["LineDataPointStyle"]; List<Setter> setterList = new List<Setter>(); foreach (Setter setter in style.Setters) setterList.Add(setter); style = new Style(); foreach (var setter in setterList) style.Setters.Add(setter); style.Setters.Add(new Setter(LineSeries.TemplateProperty, null)); lineSeriesActualValue.DataPointStyle = style; } else lineSeriesActualValue.DataPointStyle = (Style)this.Resources["LineDataPointStyle"]; break; case ChartTypes.Area: this.chartView.Series.Add(new AreaSeries()); lineSeriesActualValue = this.chartView.Series[0] as AreaSeries; break; default: break; } if (!lineSeriesActualValue.IsNull()) { lineSeriesActualValue.IsSelectionEnabled = true; lineSeriesActualValue.DependentValuePath = FieldForDependentValue; lineSeriesActualValue.IndependentValuePath = FieldForIndependentValue; lineSeriesActualValue.ItemsSource = GenerateActualValues(); // Adding a max limit to chart if (!ItemsSource.IsNull() && ((!GetMaxLimitValue1(this).IsNull()) && !GetMaxLimitValue1(this).Equals(0.0))) { this.chartView.Series.Add(new LineSeries()); lineSeriesMaxValue1 = this.chartView.Series[1] as LineSeries; Style styleMaxLineSeries = new Style(); styleMaxLineSeries.Setters.Add(new Setter(LineSeries.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 234, 178, 15)))); styleMaxLineSeries.Setters.Add(new Setter(LineSeries.TemplateProperty, null)); lineSeriesMaxValue1.DataPointStyle = styleMaxLineSeries; lineSeriesMaxValue1.DependentValuePath = FieldForDependentValue; lineSeriesMaxValue1.IndependentValuePath = FieldForIndependentValue; lineSeriesMaxValue1.ItemsSource = GenerateLimitValues("Max1"); if (this.chartView.Series.Contains(lineSeriesMaxValue1)) this.chartView.Series.Remove(lineSeriesMaxValue1); this.chartView.Series.Add(lineSeriesMaxValue1); } // Adding a min limit to chart if (!ItemsSource.IsNull() && ((!GetMinLimitValue1(this).IsNull()) && !GetMinLimitValue1(this).Equals(0.0))) { this.chartView.Series.Add(new LineSeries()); lineSeriesMinValue1 = this.chartView.Series[2] as LineSeries; Style styleMinLineSeries = new Style(); styleMinLineSeries.Setters.Add(new Setter(LineSeries.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 234, 178, 15)))); styleMinLineSeries.Setters.Add(new Setter(LineSeries.TemplateProperty, null)); lineSeriesMinValue1.DataPointStyle = styleMinLineSeries; lineSeriesMinValue1.DependentValuePath = FieldForDependentValue; lineSeriesMinValue1.IndependentValuePath = FieldForIndependentValue; lineSeriesMinValue1.ItemsSource = GenerateLimitValues("Min1"); if (this.chartView.Series.Contains(lineSeriesMinValue1)) this.chartView.Series.Remove(lineSeriesMinValue1); this.chartView.Series.Add(lineSeriesMinValue1); } // Adding a target value to chart if (!ItemsSource.IsNull() && ((!GetTargetValue(this).IsNull()) && !GetTargetValue(this).Equals(0.0))) { this.chartView.Series.Add(new LineSeries()); lineSeriesTarget = this.chartView.Series[3] as LineSeries; Style styleTargetLineSeries = new Style(); styleTargetLineSeries.Setters.Add(new Setter(LineSeries.BackgroundProperty, Brushes.Gray)); styleTargetLineSeries.Setters.Add(new Setter(LineSeries.TemplateProperty, null)); lineSeriesTarget.DataPointStyle = styleTargetLineSeries; lineSeriesTarget.DependentValuePath = FieldForDependentValue; lineSeriesTarget.IndependentValuePath = FieldForIndependentValue; lineSeriesTarget.ItemsSource = GenerateLimitValues("Target"); if (this.chartView.Series.Contains(lineSeriesTarget)) this.chartView.Series.Remove(lineSeriesTarget); this.chartView.Series.Add(lineSeriesTarget); } // Adding a max limit to chart if (!ItemsSource.IsNull() && ((!GetMaxLimitValue2(this).IsNull()) && !GetMaxLimitValue2(this).Equals(0.0))) { this.chartView.Series.Add(new LineSeries()); lineSeriesMaxValue2 = this.chartView.Series[4] as LineSeries; Style styleMaxLineSeries = new Style(); styleMaxLineSeries.Setters.Add(new Setter(LineSeries.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 255, 0, 0)))); styleMaxLineSeries.Setters.Add(new Setter(LineSeries.TemplateProperty, null)); lineSeriesMaxValue2.DataPointStyle = styleMaxLineSeries; lineSeriesMaxValue2.DependentValuePath = FieldForDependentValue; lineSeriesMaxValue2.IndependentValuePath = FieldForIndependentValue; lineSeriesMaxValue2.ItemsSource = GenerateLimitValues("Max2"); if (this.chartView.Series.Contains(lineSeriesMaxValue2)) this.chartView.Series.Remove(lineSeriesMaxValue2); this.chartView.Series.Add(lineSeriesMaxValue2); } // Adding a min limit to chart if (!ItemsSource.IsNull() && ((!GetMinLimitValue2(this).IsNull()) && !GetMinLimitValue2(this).Equals(0.0))) { this.chartView.Series.Add(new LineSeries()); lineSeriesMinValue2 = this.chartView.Series[5] as LineSeries; Style styleMinLineSeries = new Style(); styleMinLineSeries.Setters.Add(new Setter(LineSeries.BackgroundProperty, new SolidColorBrush(Color.FromArgb(255, 255, 0, 0)))); styleMinLineSeries.Setters.Add(new Setter(LineSeries.TemplateProperty, null)); lineSeriesMinValue2.DataPointStyle = styleMinLineSeries; lineSeriesMinValue2.DependentValuePath = FieldForDependentValue; lineSeriesMinValue2.IndependentValuePath = FieldForIndependentValue; lineSeriesMinValue2.ItemsSource = GenerateLimitValues("Min2"); if (this.chartView.Series.Contains(lineSeriesMinValue2)) this.chartView.Series.Remove(lineSeriesMinValue2); this.chartView.Series.Add(lineSeriesMinValue2); } // Configure axis if (ItemsSource.IsNull() || (((IList)ItemsSource).Count == 0)) { foreach (var actualAxis in this.chartView.ActualAxes) if (actualAxis.Orientation.Equals(AxisOrientation.Y)) { (actualAxis as LinearAxis).Maximum = null; (actualAxis as LinearAxis).Minimum = null; (actualAxis as LinearAxis).ShowGridLines = ShowGridLinesY; (actualAxis as LinearAxis).Visibility = Visibility.Collapsed; } else if (actualAxis.Orientation.Equals(AxisOrientation.X)) { if (actualAxis is DateTimeAxis) { if (!FieldForIndependentValue.IsNullOrEmpty() && FieldForIndependentValue.Contains("DateTime")) { (actualAxis as DateTimeAxis).Maximum = null; (actualAxis as DateTimeAxis).Minimum = null; (actualAxis as DateTimeAxis).Visibility = Visibility.Collapsed; } else (actualAxis as DateTimeAxis).Visibility = Visibility.Collapsed; } else { if (!FieldForIndependentValue.IsNullOrEmpty() && FieldForIndependentValue.Contains("Double")) { (actualAxis as LinearAxis).Maximum = null; (actualAxis as LinearAxis).Minimum = null; (actualAxis as LinearAxis).Visibility = Visibility.Collapsed; (actualAxis as LinearAxis).ShowGridLines = ShowGridLinesX; } else (actualAxis as LinearAxis).Visibility = Visibility.Collapsed; } } } else if ((this.chartView.Axes.Count > 0) && ((!ItemsSource.IsNull()) && ((IList)ItemsSource).Count > 0)) { foreach (var actualAxis in this.chartView.ActualAxes) { if (actualAxis.Orientation.Equals(AxisOrientation.Y)) { (actualAxis as LinearAxis).Maximum = null; (actualAxis as LinearAxis).Minimum = null; (actualAxis as LinearAxis).Maximum = MaximumAxisY; (actualAxis as LinearAxis).Minimum = MinimumAxisY; (actualAxis as LinearAxis).Visibility = Visibility.Visible; (actualAxis as LinearAxis).ShowGridLines = ShowGridLinesY; } else if (actualAxis.Orientation.Equals(AxisOrientation.X)) { if (actualAxis is DateTimeAxis) { if (!FieldForIndependentValue.IsNullOrEmpty() && FieldForIndependentValue.Contains("DateTime")) { (actualAxis as DateTimeAxis).Maximum = null; (actualAxis as DateTimeAxis).Minimum = null; (actualAxis as DateTimeAxis).Maximum = ((IList<ChartItems>)ItemsSource).Select(s => s.ValueXDateTime).LastOrDefault(); (actualAxis as DateTimeAxis).Minimum = ((IList<ChartItems>)ItemsSource).Select(s => s.ValueXDateTime).FirstOrDefault(); (actualAxis as DateTimeAxis).ShowGridLines = ShowGridLinesX; (actualAxis as DateTimeAxis).Visibility = Visibility.Visible; } else (actualAxis as DateTimeAxis).Visibility = Visibility.Collapsed; } else { if (!FieldForIndependentValue.IsNullOrEmpty() && FieldForIndependentValue.Contains("Double")) { (actualAxis as LinearAxis).Maximum = null; (actualAxis as LinearAxis).Minimum = null; if (IntervalAxisX > 0) (actualAxis as LinearAxis).Interval = IntervalAxisX; (actualAxis as LinearAxis).Maximum = ((IList<ChartItems>)ItemsSource).Select(s => s.ValueXDouble).LastOrDefault() + 0.5; (actualAxis as LinearAxis).Minimum = ((IList<ChartItems>)ItemsSource).Select(s => s.ValueXDouble).FirstOrDefault() - 0.5; (actualAxis as LinearAxis).Visibility = Visibility.Visible; (actualAxis as LinearAxis).ShowGridLines = ShowGridLinesX; } else (actualAxis as LinearAxis).Visibility = Visibility.Collapsed; } } } } } } 

Any help would be appreciated.

Best regards, Gustavo.

+1
source share
1 answer

As it turned out, it's easy to add custom elements to the chart. You should get the chart area, calculate the positions of your elements and just add them when adding to any panel.

Here is a complete example:

 private Canvas canvas; public MainWindow() { InitializeComponent(); chart.Loaded += this.OnChartLoaded; } private void OnChartLoaded(object sender, RoutedEventArgs e) { var chartArea = (Panel)chart.GetType().GetProperty("ChartArea", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(chart, null); // create a canvas to which all text blocks will be added this.canvas = new Canvas(); chartArea.Children.Add(this.canvas); } public void AddAllLineLabels() { // add a red label double value = 15; var text = new TextBlock() { Text = value.ToString(), Foreground = Brushes.Red }; AddTextToCanvas(canvas, text, value); // add a green label value = 19; text = new TextBlock() { Text = value.ToString(), Foreground = Brushes.Green }; AddTextToCanvas(canvas, text, value); } private void AddTextToCanvas(Canvas canvas, TextBlock text, double value) { var valuesAxis = chart.ActualAxes.OfType<LinearAxis>().FirstOrDefault(ax => ax.Orientation == AxisOrientation.Y); var min = valuesAxis.ActualMinimum.Value; var max = valuesAxis.ActualMaximum.Value; var maxPixels = valuesAxis.ActualHeight; var valuePixels = (value - min) / (max - min) * maxPixels; // from the bottom edge to the value in pixels Canvas.SetRight(text, 5); // 5 is a padding from the right edge, you can use any number Canvas.SetBottom(text, valuePixels); canvas.Children.Add(text); } 

If you call the AddAllLineLabels method, it displays the red number 15 and the green number 19.

+1
source

Source: https://habr.com/ru/post/958016/


All Articles