F# Winforms Charting Асинхронное обновление

Я пытаюсь создать диаграмму в winforms, которая привязывает данные к списку в памяти и обновляется динамически при изменении списка. Вот мой код:

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

Кажется, асинхронная работа работает, но диаграмма никогда ничего не показывает. Это просто показывает пустое окно. Что я делаю неправильно?

2 ответа

LinkedList<T> не может сигнализировать, что он был обновлен, поэтому Chart не может знать, когда перерисовывать себя.

Чтобы привязка данных обновляла представление, список источников должен реализовывать IBindingList и вызвать соответствующее событие, когда содержимое изменится.

Отдельно я должен отметить, что прямой доступ к свойствам / методам пользовательского интерфейса из потоков, не связанных с пользовательским интерфейсом, опасен (например, chart.IsDisposed в вашем коде). В WinForms это ограничение на самом деле редко применяется, поэтому иногда может показаться, что это работает нормально, только для того, чтобы позже произойти сбой на компьютере клиента без возможности подключить отладчик.

  • Вам нужно добавить серию в SeriesCollection графика.

    chart.Series.Add series
    
  • Вам нужно построить область диаграммы и добавить ее к ChartAreaCollection графика.

    let area = new ChartArea()
    chart.ChartAreas.Add area
    
  • Необходимо убедиться, что метод привязки данных вызывается после настройки диаграммы и формы.

    ...
    form.Controls.Add chart
    series.Points.DataBindY link
    
  • И теперь нет возможности сообщить об изменениях вашей связанной коллекции DataPointCollection из серии, как упоминалось в ответе Федора Сойкина. Я не совсем уверен, что IBindingList является соответствующим ответом; в то время как можно подключиться к ListChanged событие, мы могли бы также манипулировать сериалом " DataPointCollection непосредственно.

    let formloop = async{
        while not chart.IsDisposed do
            series.Points.RemoveAt 0
            series.Points.AddY(rnd.NextDouble()) |> ignore
            do! Async.Sleep 100 }
    
  • Наконец, я хотел бы отметить этот вклад Джона Этвуда, который затрагивает оба вопроса, поднятые Федором; проблема привязки данных (без ее использования) и проблема безопасности потока пользовательского интерфейса.
Другие вопросы по тегам