C# 图表绑定到非基本类型

C# 图表绑定到非基本类型,c#,.net,winforms,data-binding,charts,C#,.net,Winforms,Data Binding,Charts,我有一个C#.NET Windows窗体应用程序,它使用一个带有许多线系列的图表。我有一个物理设备在上面存储读数,当我下载读数时,我想让图表填充细节 我在软件中为可量化的值(如温度)创建了类型,这些值可能根据位置使用不同的单位,允许我对显示单位进行用户设置,只需处理背景中的所有内容,而不必在意,当它显示给用户时,它的单位是正确的 C#.NET Charting.Series类非常严格,当试图使用绑定数组绘制时,它抛出一个ArgumentException语句:“系列数据点不支持类型单位的值。只能

我有一个C#.NET Windows窗体应用程序,它使用一个带有许多线系列的图表。我有一个物理设备在上面存储读数,当我下载读数时,我想让图表填充细节

我在软件中为可量化的值(如温度)创建了类型,这些值可能根据位置使用不同的单位,允许我对显示单位进行用户设置,只需处理背景中的所有内容,而不必在意,当它显示给用户时,它的单位是正确的

C#.NET Charting.Series类非常严格,当试图使用绑定数组绘制时,它抛出一个ArgumentException语句:“系列数据点不支持类型单位的值。只能使用这些类型的温度值:Double、Decimal、Single、int、long、uint、ulong、String、DateTime、short、ushort”

温度类型有一个名为Value的属性,它是一个double,并且可以隐式转换为double,但这似乎并不重要。我希望有一种方法可以绑定它,这样它就可以在任何时候从结果数组中请求值时进行转换,这样它就可以正确地绘制图形,有人知道这是怎么回事吗 可以吗

我希望避免仅仅为了转换而需要LogItem[]和secondary double[]

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.
}
private LogItem[]结果;
私有异步void图形加载(对象发送方,事件参数e){
var count=wait device.LogCount.Read(CancelToken);
结果=新登录项[计数];
graph.DataSource=结果;
graph.Series[0].XValueMembers=nameof(LogItem.DateTime);//类型为System.DateTime
graph.Series[0].YValueMembers=nameof(LogItem.Temperature);//键入我的库,Units.Temperature
var prog=新的进度();
prog.ProgressChanged+=(发送者2,e2)=>{
BeginInvoke(新操作(()=>{
progBar.Value=results.Count(log=>!Equals(log,LogItem.Empty));
CheckEmptyPoints();//设置或清除点[x]。IsEmpty;
graph.Invalidate();//强制graph绘制新结果,也许是更好的方法?
}));
};
等待设备。下载日志(CancelToken、results、prog);//获取输出缓冲区和IProgress以报告已下载的更多数据。
}

您可以使用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
或任何合适的标签

非常感谢
Reza Aghaei
的帮助

Linq语句确实包含了提供转换函数的答案,但只需稍加调整,就不会创建新数组,也不会在每次刷新时重新绑定

解决方案是使用
Charting.datapointscolection.DataBind(IEnumerable dataSource,string xField,string yField,string otherFields)
绑定到数据。但要使用Linq语句创建要在数据绑定中使用的IEnumerable对象,并且在每次调用MoveNext时,此IEnumerable将从数组中获取数据并转换为图表

// 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);
//IEnumerable.Select(…)创建一个引用数组的IEnumerable,
//并在每次调用MoveNext()时执行选择和转换。
graph.Series[0].Points.DataBind(
选择(l=>new{X=l.DateTime,Y=l.OilCondition.Value}),
“X”,
“Y”,
字符串(空);

编辑:上述方法确实可以正常工作,但根据有关Points.DataBind(,,,)的文档,评估只执行一次,因此每次都需要调用DataBind(,,)方法。

我确实提到希望避免使用辅助缓冲区,而使用Linq可能更糟,因为它会不断重新分配内存。我可以修改机制,使用Points.Insert()使用系列的内部列表,并删除数据绑定。但如果知道如何做到这一点就好了。通常对于这样一个简单的查询来说,内存不是问题。但也可以使用循环和
chart1.Series[0].Points.AddXY(x,y)
将点添加到图表中。问题是我正在下载可能有数千条记录,这应该会将对象放入.NET中的LOH。。。。虽然事实上它总是保持不变的大小,所以已知的LOH问题不应该发生。我需要进一步了解Linq是如何工作的,因为我可能已经根据您的建议想到了一个解决方案。它创建了一些新对象,正如我们在
Select
语句中所要求的那样。而
AddXY
方法仅使用现有值。如果你真的需要,你可以安排一次记忆力测试。(当你的对象是普通对象时,通常你不需要这样的测试。)我有一个关于Linq如何工作的理论,但我不知道如何确认它,我在网上也找不到太多。因为所有Linq扩展语句都在IEnumerable上工作并返回IEnumerable,所以我想知道它们是否是通过调用GetEnumerator()然后创建一个新的IEnumerator来实现的。然后,可以将每个调用传递给原始枚举数,然后传递给执行该操作的Linq函数。如果这就是它在幕后的工作方式,那么这就是一个很好的转换机制。在标记答案之前,只需确认一切正常。