Richard Harrison
Richard Harrison

Reputation: 385

Creating Control on separate thread then adding to an itemsource in WPF

I am creating a control on a separate STA thread in WPF and want to add it to a list then use the list as and itemssource for an itemscontrol.

My code runs fine until I try to show the control. I get an error saying that a different thread owns the list.

I fully understand why this is, but would like to know how I can get this back on to the UI thread.

My recurring Code:

For Each S In qry
    Dim T As New System.Threading.Thread(AddressOf Loader)
    T.SetApartmentState(System.Threading.ApartmentState.STA)
    T.Start({S, AllBackgrounds})
Next

My Loader Sub:

Private Shared Sub Loader(O As Object)
    Dim ISC As New ImageSourceConverter
    Dim SI As New StudioImage
    SI.Source = ISC.ConvertFromString(O(0))
    CType(O(1), List(Of StudioImage)).Add(SI)
End Sub

So how can I get the List(Of StudioImage) back on to the UI thread?

Upvotes: 1

Views: 1071

Answers (1)

Reed Copsey
Reed Copsey

Reputation: 564403

I am creating a control on a separate STA thread in WPF and want to add it to a list then use the list as and itemssource for an itemscontrol.

You can't do this. The basic goal is flawed.

The problem is that you need to create all of the controls which will be used by WPF on the main UI thread. In WPF, FrameworkElements all have thread affinity - they need to be created and used on the same thread.

In your case, the "work" you are doing all needs to happen on the UI thread. Pushing this into background threads is never going to work properly, even if you were to properly synchronize (your code isn't thread safe, apart from the WPF side of things now).

You should just run your code entirely on the UI thread, unless there is the potential of pulling some small amount of work out that's not UI related (from what you're showing, this isn't the case).


Edit:

In your case, if you Freeze() your ImageSource, you can build the images in the background, but you can't bind them to the UI.

The following should handle this cleanly, without blocking the UI for parsing the image information.

For Each si In qry
    Dim s as String = si
    Dim t = Task.Factory.StartNew(Function() 
           Dim ISC As New ImageSourceConverter
           Dim is = ISC.ConvertFromString(s)
           is.Freeze()
           Return is
       End Function)
    t.ContinueWith(Function(a)
           Dim SI as New StudioImage
           SI.Source = a.Result
           AllBackgrounds.Add(SI)
       End Function, TaskScheduler.FromCurrentSynchronizationContext())
 Next

Upvotes: 1

Related Questions