2017-01-01 5 views
1

Ich bin mit einigen Charting-Beispielen auf dieser MSDN Seite herumspielen, aber es scheint, dass die Anwendung ein Charting-Fenster öffnet und dann unmittelbar vor dem Rendern des tatsächlichen Diagramms beendet. Hier ist das Beispiel, das ich mit dem Titel 'Daten im Hintergrund abrufen' ausführen möchte.Programm beendet vor dem Ausführen von Logik

open System 
open System.Threading 
open System.Drawing 
open System.Windows.Forms 
open FSharp.Charting 
open System.Windows.Forms.DataVisualization.Charting 

/// Add data series of the specified chart type to a chart 
let addSeries typ (chart : Chart) = 
    let series = new Series(ChartType = typ) 
    chart.Series.Add(series) 
    series 

/// Create form with chart and add the first chart series 
let createChart typ = 
    let chart = new Chart(Dock = DockStyle.Fill, Palette = ChartColorPalette.Pastel) 
    let mainForm = new Form(Visible = true, Width = 700, Height = 500) 
    let area = new ChartArea() 
    area.AxisX.MajorGrid.LineColor <- Color.LightGray 
    area.AxisY.MajorGrid.LineColor <- Color.LightGray 
    mainForm.Controls.Add(chart) 
    chart.ChartAreas.Add(area) 
    chart, addSeries typ chart 

let chart, series = createChart SeriesChartType.FastLine 
let axisX = chart.ChartAreas.[0].AxisX 
let axisY = chart.ChartAreas.[0].AxisY 

chart.ChartAreas.[0].InnerPlotPosition <- new ElementPosition(10.0f, 2.0f, 85.0f, 90.0f) 

let updateRanges (n) = 
    let values = 
     seq { 
      for p in series.Points -> p.YValues.[0] 
     } 
    axisX.Minimum <- float n - 500.0 
    axisX.Maximum <- float n 
    axisY.Minimum <- values |> Seq.min |> Math.Floor 
    axisY.Maximum <- values |> Seq.max |> Math.Ceiling 

let ctx = SynchronizationContext.Current 

let updateChart (valueX, valueY) = 
    async { 
     do! Async.SwitchToContext(ctx) 
     if chart.IsDisposed then 
      do! Async.SwitchToThreadPool() 
      return false 
     else 
      series.Points.AddXY(valueX, valueY) |> ignore 
      while series.Points.Count > 500 do 
       series.Points.RemoveAt(0) 
      updateRanges (valueX) 
      do! Async.SwitchToThreadPool() 
      return true 
    } 

let randomWalk = 
    let rnd = new Random() 

    let rec loop (count, value) = 
     async { 
      let count, value = count + 1, value + (rnd.NextDouble() - 0.5) 
      Thread.Sleep(20) 
      let! running = updateChart (float count, value) 
      if running then return! loop (count, value) 
     } 
    loop (0, 0.0) 

Async.Start(randomWalk) 

Antwort

2

Der Async.Start Betrieb startet den asynchronen Workflow im Hintergrund und dann endet, sobald die Hintergrundarbeit zu einer Warteschlange hinzugefügt wird. Wenn Ihr Programm direkt danach beendet wird, wird die Hintergrundarbeit nie ausgeführt.

Wenn Sie Anwendung mit Windows Forms schreiben, dann müssen Sie wahrscheinlich so etwas wie:

Async.Start(randomWalk) 
Application.Run(mainForm) 

Der Start Anruf wird die Arbeit und die Run Anruf planen Kontrolle zu Windows Forms geben wird die Anwendung bis mainForm laufen ist geschlossen. In anderen Kontexten könnten Sie das anders handhaben - im Skript würde Ihr Code funktionieren, weil F # Interactive die Hintergrundarbeit nach Ausführung eines Befehls weiter ausführt. In einer Konsolenanwendung können Sie Console.ReadLine ausführen und den Benutzer die Anwendung beenden lassen, indem Sie an einem beliebigen Punkt die EINGABETASTE drücken.

Verwandte Themen