简体   繁体   English

F#Winforms图表异步更新

[英]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 } 
  • Finally I'd like to point out this contribution by John Atwood which adresses both points raised by Fyodor; 最后,我想指出约翰·阿特伍德(John Atwood) 所做的贡献 ,它解决了费奥多(Fyodor)提出的两点。 the data binding issue (by not using it) and the UI-thread safety issue. 数据绑定问题(不使用它)和UI线程安全性问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM