我有一个C#.NET Windows窗体应用程序使用带有许多行系列的图表。 我有一个物理设备存储读数,当我下载读数时,我希望图表填写详细信息。
我已经在软件中创建了可以量化的值(例如温度)的类型,可以根据位置使用不同的单位,允许我为显示单位设置用户,只需处理背景中的所有内容而无需关心,以及何时显示对于用户来说,它是在正确的单位。
C#.NET Charting.Series类非常严格,当尝试使用绑定数组进行绘制时,它会抛出一个带有以下语句的ArgumentExeption:“系列数据点不支持Units.Temperature类型的值,只能使用这些类型的值: Double,Decimal,Single,int,long,uint,ulong,String,DateTime,short,ushort“。
Temperature类型有一个名为Value的属性,它是一个double,也可以隐式转换为double,但这似乎并不重要。 我希望有一种方法可以绑定它,以便它在每次请求结果数组中的值时进行转换,这样它就可以正确地绘制图形,任何人都知道如何做到这一点?
我希望避免使用LogItem [],然后只需要转换的辅助双[]。
private LogItem[] results; private async void GraphPage_Load(object sender, EventArgs e) { var count = await device.LogCount.Read(CancelToken); results = new LogItem[count]; graph.DataSource = results; graph.Series[0].XValueMembers = nameof(LogItem.DateTime); //Type is System.DateTime graph.Series[0].YValueMembers = nameof(LogItem.Temperature); //Type my library, Units.Temperature var prog = new Progress<double>(); prog.ProgressChanged += (sender2, e2) => { BeginInvoke(new Action(() => { progBar.Value = results.Count(log => !Equals(log, LogItem.Empty)); CheckEmptyPoints(); //Sets or clears Points[x].IsEmpty; graph.Invalidate(); //Force graph to draw new results, maybe a better way of doing this? })); }; await device.DownloadLogs(CancelToken, results, prog); //Takes output buffer and IProgress to report more data has been downloaded. }I have a C#.NET Windows Forms application using a chart with a number of line series. I have a physical device that stores readings on it, and as I'm downloading the readings I want the graph to fill in the detail.
I have created types in the software for quantifiable values (such as temperature) that may use different units depending on location, allowing me to have a user setting for display units, and just deal with everything in the background without caring, and when it's displayed to the user it's in the correct unit.
The C#.NET Charting.Series class is very strict and when attempting to draw using the bound array it throws an ArgumentExeption with the statement: "Series data points do not support values of type Units.Temperature only values of these types can be used: Double, Decimal, Single, int, long, uint, ulong, String, DateTime, short, ushort".
The Temperature type has a property called Value which is a double, and also is implicitly convertible to double, but this doesn't seem to matter. I'm hoping there's a way to bind this so that it converts whenever it requests the value from the results array so it can draw the graph correctly, anybody know how this might be done?
I'm hoping to avoid the need to the LogItem[] and then a secondary double[] just for the conversion.
private LogItem[] results; private async void GraphPage_Load(object sender, EventArgs e) { var count = await device.LogCount.Read(CancelToken); results = new LogItem[count]; graph.DataSource = results; graph.Series[0].XValueMembers = nameof(LogItem.DateTime); //Type is System.DateTime graph.Series[0].YValueMembers = nameof(LogItem.Temperature); //Type my library, Units.Temperature var prog = new Progress<double>(); prog.ProgressChanged += (sender2, e2) => { BeginInvoke(new Action(() => { progBar.Value = results.Count(log => !Equals(log, LogItem.Empty)); CheckEmptyPoints(); //Sets or clears Points[x].IsEmpty; graph.Invalidate(); //Force graph to draw new results, maybe a better way of doing this? })); }; await device.DownloadLogs(CancelToken, results, prog); //Takes output buffer and IProgress to report more data has been downloaded. }最满意答案
您可以使用linq将结果整形为图表友好的形状。 例如:
var list = results.Select(x => new { X = x.DateTime, Y = x.Temprature.Value }).ToList(); this.chart1.DataSource = list; this.chart1.Series[0].XValueMember = "X"; this.chart1.Series[0].YValueMembers = "Y";X和Y只是占位符,您可以使用DateTime和Tempratue或任何合适的标签。
Many thanks to Reza Aghaei for the help.
The Linq statements do hold the answer to providing a conversion function, but just with a little tweaking so it's not creating a new array and rebinding with every refresh.
The solution is to use Charting.DataPointsCollection.DataBind(IEnumerable dataSource, string xField, string yField, string otherFields) to bind to the data. But to use Linq statements to create an IEnumerable object to be used in the databind, and on every call of MoveNext, this IEnumerable will fetch the data from the array and convert for the chart.
// IEnumerable<LogItem>.Select(...) creates an IEnumerable which references the array, // and performs the selection and conversion on each call to MoveNext(). graph.Series[0].Points.DataBind( results.Select(l => new { X = l.DateTime, Y = l.OilCondition.Value }), "X", "Y", string.Empty);EDIT: The above does work correctly, but according to the documentation on Points.DataBind(,,,), the evaluation is only performed once, so the DataBind(,,,) method does need to be called each time.
更多推荐
发布评论