2015-03-31 5 views
0

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

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 

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

ответ

3

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

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

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

0
  • Вам необходимо добавить серию в таблицу SeriesCollection.

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

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

    ... 
    form.Controls.Add chart 
    series.Points.DataBindY link 
    
  • А теперь нет никакого способа сообщить изменения вашей связанной коллекции к DataPointCollection серии, как уже упоминалось в Fyodor Soikin's answer. Я не совсем уверен, что 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 } 
    
  • Наконец, я хотел бы отметить, это contribution Джона Этвуд, который АДРЕС обе точки, поставленный Федором; проблема с привязкой данных (не используя ее) и проблему безопасности пользовательского интерфейса.