Silverlight CompositionHost.Initialize / New DeploymentCatalog on a Background Thread?

Jun 30, 2010 at 9:20 PM

Hello,

I'm making use of partitioned XAPs and overriding the CompositionContainer with something like this.

AggregateCatalog.Catalogs.Add(New DeploymentCatalog())
_Container = New CompositionContainer(AggregateCatalog)
_Container.ComposeExportedValue(AggregateCatalog)
CompositionHost.Initialize(_Container)
'Register for XAP updates via PollingDuplex service

 Is it possible to do something like this on a background thread in Silverlight via a Background worker?  Or, does this all have to occur on the UI thread in Silverlight?  I'm trying to avoid blocking the UI thread while this initialization is taking place.  Any ideas?

-Nick


Jul 1, 2010 at 2:31 PM

Ideally I'm looking to do something like this:

        Dim bw As New CustomBackgroundWorker
        bw.DoWorkHandler =
            Sub(sender As Object, e As DoWorkEventArgs)
                Dim aggregateCatalog As New AggregateCatalog
                aggregateCatalog.Catalogs.Add(New DeploymentCatalog())
                Dim container As CompositionContainer
                container = New CompositionContainer(aggregateCatalog)
                container.ComposeExportedValue(aggregateCatalog)
                CompositionHost.Initialize(container)
            End Sub
        bw.RunWorkerAsync()
It seems that the default constructor for DeploymentCatalog accesses System.Windows.Deployment.get_Parts to get all of the assemblies in the default XAP.
System.Windows.Deployment is a dependency object, so the call to get_Parts blows up, as it is a DependencyProperty.
Is there a way I could tinker with the DeploymentCatalog (ideally) or write my own ComposablePartCatalog that would allow me to pass in the assembly list? 
I suspect that once I get around the System.Windows.Deployment.get_Parts call, the rest of the deployment catalog will support running on the background thread.
It looks like I could inherit from DeploymentCatalog and write my own constructor, however, I won't be able to set any of the private variables.
Any suggestions would be most appreciated.
Thanks,
-Nick
Jul 1, 2010 at 2:56 PM

Ah, nevermind.  You guys seem to have thought of everything already.  Bravo!  Looks like what I needed is already built into the AssemblyCatalog.  Here's what worked for anyone else that is interested. 

Partial Public Class MainPage
    Inherits UserControl

    Public Sub New()
        InitializeComponent()

        Dim bw As New CustomBackgroundWorker
        bw.DoWorkHandler =
            Sub(sender As Object, e As DoWorkEventArgs)
                Dim aggregateCatalog As New AggregateCatalog

                Dim args As IEnumerable(Of Tuple(Of AssemblyPart, StreamResourceInfo)) =
                    DirectCast(e.Argument, IEnumerable(Of Tuple(Of AssemblyPart, StreamResourceInfo)))
                Dim list As New List(Of Assembly)

                For Each tuple As Tuple(Of AssemblyPart, StreamResourceInfo) In args
                    Dim item As Assembly = tuple.Item1.Load(tuple.Item2.Stream)
                    list.Add(item)
                Next

                For Each assembly As Assembly In list
                    aggregateCatalog.Catalogs.Add(New AssemblyCatalog(assembly))
                Next
                Dim container As CompositionContainer
                container = New CompositionContainer(aggregateCatalog)
                container.ComposeExportedValue(aggregateCatalog)
                CompositionHost.Initialize(container)

                CompositionInitializer.SatisfyImports(Me)
            End Sub
        bw.RunWorkerAsync(GetAssemblies())
    End Sub

    Private Function GetAssemblies() As IEnumerable(Of Tuple(Of AssemblyPart, StreamResourceInfo))
        Dim list As New List(Of Tuple(Of AssemblyPart, StreamResourceInfo))
        For Each part As AssemblyPart In Deployment.Current.Parts
            Dim resourceStream As StreamResourceInfo = Application.GetResourceStream(New Uri(part.Source, UriKind.Relative))
            If resourceStream IsNot Nothing Then
                list.Add(New Tuple(Of AssemblyPart, StreamResourceInfo)(part, resourceStream))
            End If
        Next
        Return list
    End Function

    <Import()>
    Public Property Class1 As Class1
End Class

<Export()>
Public Class Class1

End Class

Public Class CustomBackgroundWorker
    Inherits BackgroundWorker

    Private _DoWorkHandler As DoWorkEventHandler
    Public WriteOnly Property DoWorkHandler As DoWorkEventHandler
        Set(ByVal value As DoWorkEventHandler)
            If _DoWorkHandler IsNot Nothing Then
                RemoveHandler Me.DoWork, _DoWorkHandler
            End If
            _DoWorkHandler = value
            AddHandler Me.DoWork, _DoWorkHandler
        End Set
    End Property

End Class