Я работал над созданием программы в UWP, которая использует элементы управления Telerik Charting для отображения входящих данных пользователю. В моем последнем тестировании с получением незапрошенных данных и их динамического отображения на диаграмме я обнаружил, что происходит необработанное исключение (NullReferenceException). Похоже, это происходит только тогда, когда пользователь наводит указатель мыши на диаграмму с диаграммой, показывающей информацию о трекбале (Telerik's ChartTrackBallBehavior). Если пользовательская мышь находится в другом месте или иным образом не активировала информацию TrackBall для отображения на графике, это исключение никогда не достигается.
Мне до сих пор удавалось отследить исключение NullException, возникающее в функции GetIntersectionTemplate () в ChartTrackBallBehavior.cs в пользовательском интерфейсе Telerik для UWP. Кроме того, я не знаю, что я могу сделать для решения этой проблемы, чтобы она никогда не повторилась.
Вот типичная трассировка стека, когда происходит исключение:
System.ArgumentNullException: Value cannot be null.
at Telerik.UI.Xaml.Controls.Chart.ChartTrackBallBehavior.GetIntersectionTemplate(DependencyObject instance)
at Telerik.UI.Xaml.Controls.Chart.ChartTrackBallBehavior.UpdateIntersectionPoints(ChartDataContext context)
at Telerik.UI.Xaml.Controls.Chart.ChartTrackBallBehavior.UpdateVisuals()
at Telerik.UI.Xaml.Controls.Chart.RadChartBase.NotifyUIUpdated()
at Telerik.UI.Xaml.Controls.Chart.PresenterBase.UpdateUI(ChartLayoutContext context)
Я пытался отключить ChartTrackBallBehavior до и после добавления каждой серии в диаграмму, но безрезультатно.
Я попытался вручную изменить фокус на другой элемент управления, кроме Chart, но безрезультатно.
Я пробовал ручные вызовы Chart.UpdateLayout () в разных областях, только чтобы эти вызовы создавали одно и то же исключение NullReferenceException в одном и том же месте (ChartTrackBallBehavior.cs).
В основе проблемы, по-видимому, лежит это «Значение», которое по ошибке установлено в ноль. До сих пор я не смог определить, какое значение «Value» вообще установлено в null, я могу только предположить, что оно попадает в вызов NullReferenceException throw () в вызове функции GetIntersectionTemplate (). Но я не знаю, почему это происходит или что я могу с этим поделать.
Я сделал минимальный проект, который повторяет проблему. Обратите внимание, что он очищает все серии с графика, а затем перерисовывает все серии на графике. Это сделано для того, чтобы быть эквивалентным моему собственному проекту, и, похоже, связано с самой проблемой. Процедура очистки и повторного добавления серии выполняется, поскольку пользователь может в любое время изменить, какие серии должны быть показаны на диаграмме.
Возможно, я смогу изменить структуру кодирования, чтобы подойти к этому с другой стороны, но в настоящее время я хотел бы лучше понять, что вызывает эту проблему, и решить ее, если смогу, так как в противном случае мне, вероятно, потребуется переписать большую часть кода, и, к сожалению, время не на моей стороне с этим.
Вот пример кода. Обратите внимание, что для этого кода я использую Telerik.UI.for.UniversalWindowsPlatform версии 1.0.1.5.
MainPage.xaml
<Page
x:Class="ExceptionReplicator.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ExceptionReplicator"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:telerikChart="using:Telerik.UI.Xaml.Controls.Chart"
xmlns:telerikPrimitives="using:Telerik.UI.Xaml.Controls.Primitives"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<telerikChart:RadCartesianChart x:Name="MainChart" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,10,10,10">
<telerikChart:RadCartesianChart.Grid>
<telerikChart:CartesianChartGrid MajorLinesVisibility="XY"/>
</telerikChart:RadCartesianChart.Grid>
<telerikChart:RadCartesianChart.Behaviors>
<telerikChart:ChartPanAndZoomBehavior ZoomMode="Both" PanMode="Both"/>
<telerikChart:ChartTrackBallBehavior x:Name="TrackBallBehaviour" InfoMode="Multiple" ShowIntersectionPoints="True">
<telerikChart:ChartTrackBallBehavior.LineStyle>
<Style TargetType="Polyline">
<Setter Property="Stroke" Value="Tomato"/>
<Setter Property="StrokeThickness" Value="2"/>
<Setter Property="StrokeDashArray" Value="1,2"/>
</Style>
</telerikChart:ChartTrackBallBehavior.LineStyle>
<telerikChart:ChartTrackBallBehavior.IntersectionTemplate>
<DataTemplate>
<Ellipse Width="10" Height="10" Fill="Tomato"/>
</DataTemplate>
</telerikChart:ChartTrackBallBehavior.IntersectionTemplate>
</telerikChart:ChartTrackBallBehavior>
</telerikChart:RadCartesianChart.Behaviors>
<telerikChart:RadCartesianChart.VerticalAxis>
<telerikChart:LinearAxis x:Name="Vertical" Title="Y Axis" Minimum="0"/>
</telerikChart:RadCartesianChart.VerticalAxis>
<telerikChart:RadCartesianChart.HorizontalAxis>
<telerikChart:LinearAxis x:Name="Horizontal" Title="X Axis"/>
</telerikChart:RadCartesianChart.HorizontalAxis>
</telerikChart:RadCartesianChart>
</Grid>
</Page>
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace ExceptionReplicator
{
using System;
using System.Threading;
using Telerik.UI.Xaml.Controls.Chart;
using Windows.UI.Core;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private Timer DataTimer; // timer to periodically add data to the chart
private int LineCount = 1; // arbitrary line counter to differentiate lines from each other
// custom class for holding the data to be displayed on the chart
private class Data
{
public int XValue { get; set; }
public int YValue { get; set; }
}
// overarching class that holds all of the data for ONE line/series
private class DataToChart
{
// List of all the data points within this instance of DataToChart
public List<Data> DataPoints;
// Constructor to initialise DataPoints
public DataToChart()
{
DataPoints = new List<Data>();
}
}
// Overarching container to hold data for ALL lines/series
private List<DataToChart> allData = new List<DataToChart>();
public MainPage()
{
this.InitializeComponent();
// set up the timer to call every 10s to add new data to the chart. warning: this will run infinitely
DataTimer = new Timer(DataCallback, null, (int)TimeSpan.FromSeconds(10).TotalMilliseconds, Timeout.Infinite);
}
// Generic callback to call AddLineToChart() on the other thread to handle the Chart's data
private void DataCallback(object state)
{
var task = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => AddLineToChart());
}
// Code to handle adding a line to the chart
private void AddLineToChart()
{
// Using Random() to create random data
Random rand = new Random();
DataToChart dataToChart = new DataToChart();
for (int i = 0; i < 50; i++)
{
dataToChart.DataPoints.Add(new Data
{
XValue = i,
YValue = rand.Next(0, 100)
});
}
// Add the data for this line/series to the overarching container
allData.Add(dataToChart);
// re-initialise the line count
LineCount = 1;
// Currently the code needs to clear the chart and redraw it each time new data is introduced
MainChart.Series.Clear();
// For each line/series in the main container
foreach (DataToChart data in allData)
{
// Make a series for the line
ScatterLineSeries scatterLineSeries = new ScatterLineSeries
{
Name = $"Line {LineCount}",
ItemsSource = dataToChart.DataPoints,
XValueBinding = new PropertyNameDataPointBinding("XValue"),
YValueBinding = new PropertyNameDataPointBinding("YValue"),
DisplayName = $"Line {LineCount}",
LegendTitle = $"Line {LineCount}",
};
// Add the line to the Chart's Series collection
MainChart.Series.Add(scatterLineSeries);
// Increment arbitrary counter
LineCount++;
}
// Re-set the timer to fire again in 10s
DataTimer.Change((int)TimeSpan.FromSeconds(10).TotalMilliseconds, Timeout.Infinite);
}
}
}
Мне нужно найти решение, чтобы это исключение больше не возникало при вводе новых данных. Любая помощь будет принята с благодарностью.
В краткосрочной перспективе я полностью удалил ChartTrackBallBehavior из своей Диаграммы (закомментировал ее) до тех пор, пока не найду решение. При удаленном поведении это исключение не возникает.