2011-07-05 67 views
1

IEvent這個F#代碼丟失,需要幫助,使在這個代碼..我不明白如何使觸發事件需要幫助從專家F#第13章

// ---------------------------- 
// Listing 13-3. 

open System 
open System.Threading 
open System.ComponentModel 
open System.Windows.Forms 

/// An IterativeBackgroudWorker follows the BackgroundWorker design pattern 
/// but instead of running an arbitrary computation it iterates a function 
/// a fixed number of times and reports intermediate and final results. 
/// The worker is paramaterized by its internal state type. 
/// 
/// Percentage progress is based on the iteration number. Cancellation checks 
/// are made at each iteration. Implemented via an internal BackgroundWorker. 
type IterativeBackgroundWorker<'a>(oneStep:('a -> 'a), 
            initialState:'a, 
            numIterations:int) = 

    let worker = 
     new BackgroundWorker(WorkerReportsProgress=true, 
          WorkerSupportsCancellation=true) 

    // The constructor captures the synchronization context. This allows us to post 
    // messages back to the GUI thread where the BackgroundWorker was created. 
    let syncContext = SynchronizationContext.Current 
    do if syncContext = null then failwith "no synchronization context found" 

    // Create the events that we will later trigger 
    let triggerStarted, started = IEvent.create() 
    let triggerCompleted,completed = IEvent.create() 
    let triggerError ,error  = IEvent.create() 
    let triggerCancelled,cancelled = IEvent.create() 
    let triggerProgress ,progress = IEvent.create() 

    do worker.DoWork.Add(fun args -> 
     syncContext.Post(SendOrPostCallback(fun _ -> triggerStarted(DateTime.Now)), 
         state=null) 

     // This recursive function represents the computation loop. 
     // It runs at "maximum speed", i.e. is an active rather than 
     // a reactive process, and can only be controlled by a 
     // cancellation signal. 
     let rec iterate state i = 
      // At the end of the compuation terminate the recursive loop 
      if worker.CancellationPending then 
       args.Cancel <- true 
      elif i < numIterations then 
       // Compute the next result 
       let state' = oneStep state 

       // Report the percentage compuation and the internal state 
       let percent = int ((float (i+1)/float numIterations) * 100.0) 
       do worker.ReportProgress(percent, box state); 

       // Compute the next result 
       iterate state' (i+1) 
      else 
       args.Result <- box state 

     iterate initialState 0) 

    do worker.RunWorkerCompleted.Add(fun args -> 
     if args.Cancelled  then triggerCancelled() 
     elif args.Error <> null then triggerError args.Error 
     else triggerCompleted (args.Result :?> 'a)) 

    do worker.ProgressChanged.Add(fun args -> 
     triggerProgress (args.ProgressPercentage,(args.UserState :?> 'a))) 

    member x.WorkerCompleted = completed 
    member x.WorkerCancelled = cancelled 
    member x.WorkerError  = error 
    member x.ProgressChanged = progress 

    // Delegate the remaining members to the underlying worker 
    member x.RunWorkerAsync() = worker.RunWorkerAsync() 
    member x.CancelAsync()  = worker.CancelAsync() 

    /// The Started event gets raised when the worker starts. It is 
    /// raised on the GUI thread (i.e. in the synchronization context of 
    /// the thread where the worker object was created). 
    // It has type IEvent<DateTime> 
    member x.Started    = started 

let fibOneStep (fibPrevPrev:bigint,fibPrev) = (fibPrev, fibPrevPrev+fibPrev) 

// ---------------------------- 

let worker = new IterativeBackgroundWorker<_>(fibOneStep,(1I,1I),100) 

worker.WorkerCompleted.Add(fun result -> 
     MessageBox.Show(sprintf "Result = %A" result) |> ignore) 

worker.ProgressChanged.Add(fun (percentage, state) -> 
    printfn "%d%% complete, state = %A" percentage state) 

worker.RunWorkerAsync() 

// ---------------------------- 

只需要知道如何做一個將在稍後觸發的新事件。但是,如果有人想幫助,使在代碼那麼這將是一個很大的感謝:d

+0

http://msdn.microsoft.com/en-us/library/dd233189.aspx – Daniel

回答

1

從文檔:

open System.Collections.Generic 

type MyClassWithCLIEvent() = 

    let event1 = new Event<_>() 

    [<CLIEvent>] 
    member this.Event1 = event1.Publish 

    member this.TestEvent(arg) = 
     event1.Trigger(this, arg) 

let classWithEvent = new MyClassWithCLIEvent() 
classWithEvent.Event1.Add(fun (sender, arg) -> 
     printfn "Event1 occurred! Object data: %s" arg) 

classWithEvent.TestEvent("Hello World!") 
1

發表丹尼爾的代碼應該給你答案。只是鏈接,從(第一版)的專家F#的書的代碼,修改爲:

  • IEvent.create()功能已被更換不同類型,所以你會使用new Event<_>()
  • 第一返回的元組(觸發功能)的元件是所述對象的Trigger構件
  • 元組(IEvent值)的第二個要素是所述物體的Publish構件
  • 如果使用CLIEvent屬性,事件將被編譯爲.NET事件(否則它會只是IEvent類型的一個屬性)

我相信這些是在API中處理事件的唯一突破性更改。還有一個新模塊Observable,它包含與Event(例如Event.map)相同的功能,通常使用可觀察的實現(它更標準並避免潛在的內存泄漏)更好。