I call this this function from the GUI thread:
let updateImageLoop (pprocess : PlotProcess) (target : IUpdatableImageView<'T>) =
async {
while target.Continue do
let context = System.Threading.SynchronizationContext.Current
do! Async.SwitchToThreadPool()
System.Threading.Thread.Sleep(10000)
do! Async.SwitchToContext(context)
let image = target.CreateImage()
match image with
| Some userImage -> do! target.UpdateImageView userImage
| None -> ()
} |> Async.StartImmediate
The problem comes when the method target.UpdateImageView is executed, an exception is generated:
The calling thread must be STA, because many UI components require this.
I know that, but that is what i did with
do! Async.SwitchToContext(context)
Eliminating the functions SwitchToContext and SwitchToThreadPool, removes the exception, but the GUI just freezes. And that makes sense, but why i can't make the switch between threads??
The function that generates the problem is UpdateImageView. I tested it with and without making it async.
member this.UpdateImageView etoimage =
async {
let imageview = new Eto.Forms.ImageView()
imageview.Image <- etoimage
this.Content <- imageview
}
edit ---
Testing with this code:
let updateImageLoop (pprocess : PlotProcess) (target : IUpdatableImageView<'T>) =
let context = System.Threading.SynchronizationContext.Current
let printThread text =
printfn "[%d] %s" System.Threading.Thread.CurrentThread.ManagedThreadId text
async {
while target.Continue do
printThread "begining"
do! Async.SwitchToThreadPool()
printThread "after swith to thread pool"
let image = target.CreateImage()
match image with
| Some userImage ->
printThread "before switch to context"
do! Async.SwitchToContext context
printThread "after switch to context"
target.UpdateImageView userImage
| None -> ()
} |> Async.StartImmediate
Prints :
[1] begining
[4] after swith to thread pool
[4] before switch to context
[5] after switch to context
1 Answer 1
Use [< STAThread>]
Use the guiContext to work on the GUI
In your GUI creation (framework init) remember the guiContext
let guiContext = System.Threading.SynchronizationContext.Current
and pass it into async GUI execute
// the async GUI execute
async {
let currentContext = System.Threading.SynchronizationContext.Current
do! Async.SwitchToContext(guiContext)
f() // work on the GUI
do! Async.SwitchToContext(currentContext)
}
Put the waiting in an extra step to keep it composable.
1 Comment
Explore related questions
See similar questions with these tags.
[<STAThread>]attribute to your assembly?UpdateImageView, perhaps it is expecting to be called on the same STA thread that created the image? That is, perhaps the library you are using expectsCreateImageandUpdateImageViewto be called on the same thread.