Sé que es posible cargar módulos xap dinámicamente utilizando el marco Prism o MEF. Sin embargo, me gustaría no usar esos marcos; En su lugar, cargue mis archivos xap manualmente. Entonces, creé la siguiente clase (adaptada de internet):silverlight 4, cargando dinámicamente módulos xap
public class XapLoader
{
public event XapLoadedEventHandler Completed;
private string _xapName;
public XapLoader(string xapName)
{
if (string.IsNullOrWhiteSpace(xapName))
throw new ArgumentException("Invalid module name!");
else
_xapName = xapName;
}
public void Begin()
{
Uri uri = new Uri(_xapName, UriKind.Relative);
if (uri != null)
{
WebClient wc = new WebClient();
wc.OpenReadCompleted += onXapLoadingResponse;
wc.OpenReadAsync(uri);
}
}
private void onXapLoadingResponse(object sender, OpenReadCompletedEventArgs e)
{
if ((e.Error == null) && (e.Cancelled == false))
initXap(e.Result);
if (Completed != null)
{
XapLoadedEventArgs args = new XapLoadedEventArgs();
args.Error = e.Error;
args.Cancelled = e.Cancelled;
Completed(this, args);
}
}
private void initXap(Stream stream)
{
string appManifest = new StreamReader(Application.GetResourceStream(
new StreamResourceInfo(stream, null), new Uri("AppManifest.xaml",
UriKind.Relative)).Stream).ReadToEnd();
XElement deploy = XDocument.Parse(appManifest).Root;
List<XElement> parts = (from assemblyParts in deploy.Elements().Elements()
select assemblyParts).ToList();
foreach (XElement xe in parts)
{
string source = xe.Attribute("Source").Value;
AssemblyPart asmPart = new AssemblyPart();
StreamResourceInfo streamInfo = Application.GetResourceStream(
new StreamResourceInfo(stream, "application/binary"),
new Uri(source, UriKind.Relative));
asmPart.Load(streamInfo.Stream);
}
}
}
public delegate void XapLoadedEventHandler(object sender, XapLoadedEventArgs e);
public class XapLoadedEventArgs : EventArgs
{
public Exception Error { get; set; }
public bool Cancelled { get; set; }
}
El código anterior funciona bien; Puedo cargar cualquier XAP de la siguiente manera:
XapLoader xapLoader = new XapLoader("Sales.xap");
xapLoader.Completed += new XapLoadedEventHandler(xapLoader_Completed);
xapLoader.Begin();
Ahora, tengo un control de usuario llamada InvoiceView en el proyecto Sales.xap, así que me gustaría crear una instancia de la clase. En el proyecto actual (Main.xap) agregué referencia al proyecto Sales.xap, sin embargo, dado que lo cargo manualmente, configuro "Copiar local = falso". Sin embargo, cuando se ejecuta, el código siguiente lanza TypeLoadException:
Sales.InvoiceView view = new Sales.InvoiceView();
Parece que el código no puede encontrar la clase InvoiceView. Pero comprobé que el método initXap() de XapLoader se ejecutó con éxito. Entonces, ¿por qué el código no puede encontrar la clase InvoiceView? ¿Puede alguien ayudarme con este problema?
Una forma más fácil de hacerlo es utilizar el Marco de Extensibilidad Administrado (MEF) que está integrado en Silverlight 4, además de .NET 4. –