The following uses the dispatcher to execute an Action delegate on the UI thread. This uses a synchronous model, the alternate Dispatcher. BeginInvoke will execute the delegate asynchronously.
The following uses the dispatcher to execute an Action delegate on the UI thread. This uses a synchronous model, the alternate Dispatcher. BeginInvoke will execute the delegate asynchronously.
Var backgroundThreadImage = GenerateImage(coordinate); GeneratedImage.Dispatcher. Invoke( DispatcherPriority. Normal, new Action(() => { GeneratedImage = backgroundThreadImage; })); UPDATE As discussed in the comments, the above alone will not work as the BitmapImage is not being created on the UI thread.
If you have no intention of modifying the image once you have created it you can freeze it using Freezable. Freeze and then assign to GeneratedImage in the dispatcher delegate (the BitmapImage becomes read-only and thus threadsafe as a result of the Freeze). The other option would be to load the image into a MemoryStream on the background thread and then create the BitmapImage on the UI thread in the dispatcher delegate with that stream and the StreamSource property of BitmapImage.
This is helpful, Simon, thanks. But how do I get around the fact that, when this process begins, GeneratedImage is not set to an instance of an object? – DanM Jun 14 '10 at 4:56 @DanM of course I didn't think about that :) You can also get hold of a Dispatcher via Application.Current.
Dispatcher – Simon Fox Jun 14 '10 at 5:02 I'm afraid this doesn't do it either. I get "The calling thread cannot access this object because a different thread owns it. " – DanM Jun 14 '10 at 5:16 Looks like you will have to create the BitmapImage on the UI thread...move the call to GenerateImage into the delegate the dispatcher is executing on the UI thread.
– Simon Fox Jun 14 '10 at 5:44 in order to do as much of the work as possible in the background thread you could read the image into a memory stream and then in the dispatcher delegate create the BitmapImage using the stream and BitmapImage. StreamSource – Simon Fox Jun 14 '10 at 5:58.
You need to do two things: Freeze your BitmapImage so it can be moved to the UI thread, then Use the Dispatcher to transition to the UI thread to set the GeneratedImage You'll need to access the UI thread's Dispatcher from the generator thread. The most flexible way to do this is to capturing the the value Dispatcher. CurrentDispatcher in the main thread and passing it into the generator thread: public void InitiateGenerateImages(List coordinates) { var dispatcher = Dispatcher.
CurrentDispatcher; var generatorThreadStarter = new ThreadStart(() => GenerateImages(coordinates, dispatcher)); ... If you know you will only use this within a running Application and that the application will only have one UI thread, you can just call Application.Current. Dispatcher to get the current dispatcher. The disadvantages are: You loose the ability to use your view model independently of a constructed Application object.
You can only have one UI thread in your application. In the generator thread, add a call to Freeze after the image is generated, then use the Dispatcher to transition to the UI thread to set the image: var backgroundThreadImage = GenerateImage(coordinate); backgroundThreadImage.Freeze(); dispatcher. BeginInvoke(DispatcherPriority.
Normal, new Action(() => { GeneratedImage = backgroundThreadImage; })); Clarification In the above code it is critical that Dispatcher. CurrentDispatcher be accessed from the UI thread, not from the generator thread. Every thread has its own Dispatcher.
If you call Dispatcher. CurrentDispatcher from the generator thread you will get its Dispatcher instead of the one you want. In other words, you must do this: var dispatcher = Dispatcher.
CurrentDispatcher; var generatorThreadStarter = new ThreadStart(() => GenerateImages(coordinates, dispatcher)); and not this: var generatorThreadStarter = new ThreadStart(() => GenerateImages(coordinates, Dispatcher. CurrentDispatcher)).
1. Thanks, Ray. I like your tip to pass in the dispatcher.
The Freeze() concept is also critical, something I know I'll need in the future. (As I commented to Simon, freeing up the UI thread wasn't really my goal in this case anyway--I was just trying to get it to update (render) each image rather than waiting until all images were processed to update. ) – DanM Jun 14 '10 at 6:41 Ray, I just tried your idea of passing in the dispatcher, but for some reason, Dispatcher.
CurrentDispatcher is not equivalent to App.Current.Dispatcher. If I use App.Current. Dispatcher, my code works perfectly, but if I pass in Dispatcher.
CurrentDispatcher, I get "The calling thread cannot access this object because a different thread owns it. " Any idea why this might be? – DanM Jun 14 '10 at 6:58 Yes, you are calling Dispatcher.
CurrentDispatcher from the generator thread not the UI thread. I've added a clarification to the answer to explain how to fix it. – Ray Burns Jun 14 '10 at 16:30 That was it.
Thanks! – DanM Jun 14 '10 at 16:57.
In the background thread work with Streams. For example, in the background thread: var artUri = new Uri("MyProject;component/../Images/artwork.placeholder. Png", UriKind.
Relative); StreamResourceInfo albumArtPlaceholder = Application. GetResourceStream(artUri); var _defaultArtPlaceholderStream = albumArtPlaceholder. Stream; SendStreamToDispatcher(_defaultArtPlaceholderStream); In the UI thread: void SendStreamToDispatcher(Stream imgStream) { dispatcher.
BeginInvoke(DispatcherPriority. Normal, new Action(() => { var imageToDisplay = new BitmapImage(); imageToDisplay. SetSource(imgStream); //Use you bitmap image obtained from a background thread as you wish!
})); }.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.