2011-07-05 11 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値)の2番目の要素は、あなたがCLIEvent属性を使用する場合、イベントは次のようにコンパイルされます
  • オブジェクトのPublishメンバーであります.NETイベント(それ以外の場合はIEventのプロパティ)

これらは、イベントを処理するためのAPIの唯一の大きな変更であると考えています。 Event(例:Event.map)と同じ機能を持つ新しいモジュールObservableもあります。一般的には、観測可能な実装を使用する方が標準的です(メモリリークの可能性はありません)。

関連する問題