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 }
- Наконец, я хотел бы отметить этот вклад Джона Этвуда, который затрагивает оба вопроса, поднятые Федором; проблема привязки данных (без ее использования) и проблема безопасности потока пользовательского интерфейса.