[英]F# Winforms Charting Asynchronous Updating
I'm trying to create a chart in winforms that databinds to a list in memory, and gets updated dynamically as the list changes. 我试图在Winforms中创建一个图表,该图表将数据绑定到内存中的列表,并随着列表的更改而动态更新。 Here is my code: 这是我的代码:
open System
open System.Linq
open System.Collections
open System.Collections.Generic
open System.Drawing
open System.Windows.Forms
open System.Windows.Forms.DataVisualization
open System.Windows.Forms.DataVisualization.Charting
let link = new LinkedList<double>()
let rnd = new System.Random()
for i in 1 .. 10 do link.AddFirst(rnd.NextDouble()) |> ignore
let series = new Series()
let chart = new System.Windows.Forms.DataVisualization.Charting.Chart(Dock = DockStyle.Fill, Palette = ChartColorPalette.Pastel)
series.Points.DataBindY(link)
let form = new Form(Visible = true, Width = 700, Height = 500)
form.Controls.Add(chart)
let formloop = async {
while not chart.IsDisposed do
link.AddFirst((new System.Random()).NextDouble()) |> ignore
link.RemoveLast()
}
do
Async.StartImmediate(formloop)
Application.Run(form)
Console.WriteLine("Done")
Console.ReadLine() |> ignore
The async seems to work, but the chart never shows anything. 异步似乎可以正常工作,但是图表从不显示任何内容。 It just shows a blank window. 它只是显示一个空白窗口。 What am I doing wrong? 我究竟做错了什么?
LinkedList<T>
has no way to signal that it's been updated, so Chart
has no way of knowing when to redraw itself. LinkedList<T>
无法表示已更新,因此Chart
无法知道何时重新绘制自身。
In order for databinding to update the view, the source list must implement IBindingList
and raise appropriate event when the contents change. 为了使数据绑定更新视图,源列表必须实现IBindingList
并在内容更改时引发适当的事件。
Separately, I must point out that it's dangerous to directly access UI properties/methods from non-UI threads (such as chart.IsDisposed
in your code). 另外,我必须指出,直接从非UI线程(例如,代码中的chart.IsDisposed
)访问UI属性/方法很危险。 In WinForms, this limitation is rarely actually enforced, so sometimes this might seem to work fine, only to crash later on a customer's machine with no way to attach a debugger. 在WinForms中,很少实际实施此限制,因此有时这似乎可以很好地工作,但稍后会在客户的计算机上崩溃,而无法附加调试器。
You need to add the series to the SeriesCollection
of the chart. 您需要将系列添加到图表的SeriesCollection
。
chart.Series.Add series
You need to construct a chart area and add it to the ChartAreaCollection
of the chart. 您需要构造一个图表区域并将其添加到图表的ChartAreaCollection
。
let area = new ChartArea() chart.ChartAreas.Add area
You need to make sure that the data binding method is called after the chart and form are set up. 您需要确保在设置图表和表单之后调用数据绑定方法。
... form.Controls.Add chart series.Points.DataBindY link
And now there's no way to communicate changes of your bound collection to the DataPointCollection
of the series, as mentioned in Fyodor Soikin's answer . 而且,正如Fyodor Soikin的答案所述,现在无法将绑定集合的更改传达给该系列的DataPointCollection
。 I'm not quite sure that IBindingList
is an appropriate response; 我不太确定IBindingList
是否合适。 while it's possible to hook into the ListChanged
event, we could as well manipulate the series' DataPointCollection
directly. 尽管可以挂接到ListChanged
事件,但我们也可以直接操纵该系列的DataPointCollection
。
let formloop = async{ while not chart.IsDisposed do series.Points.RemoveAt 0 series.Points.AddY(rnd.NextDouble()) |> ignore do! Async.Sleep 100 }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.