如何动态发现Silverlight prism应用程序中所有模块中的所有XAML文件

Gon*_*ing 8 silverlight xaml prism mvvm

有没有一种简单的方法可以动态发现所有当前加载的模块(特别是Silverlight Prism应用程序)中的所有XAML文件?我确信这是可能的,但不知道从哪里开始.

这必须在Silverlight客户端上发生:我们当然可以在开发机器上解析项目,但这会降低灵活性并在搜索中包含未使用的文件.

基本上我们希望能够解析一个非常大的Prism项目中的所有XAML文件(独立于加载它们)以识别所有本地化字符串.这将让我们构建一个初始本地化数据库,其中包括我们所有的资源绑定字符串,还可以创建查找它们所在的XAML文件(以便为翻译人员编辑).

为什么会这样?:翻译者最糟糕的事情就是在一个上下文中更改一个字符串,发现它在其他地方使用时含义略有不同.我们正在从应用程序本身启用翻译的上下文编辑.

更新(9月14日):

由于安全限制,Silverlight无法使用标准迭代程序集的方法.这意味着以下解决方案的唯一改进是尽可能与Prism模块管理合作.如果有人想为此问题的最后一部分提供代码解决方案,可以与您分享点数!

跟进:

在基于模块的项目中迭代XAP文件的内容似乎是一个非常方便的事情,因为各种原因,所以能够做另外100个代表来获得真正的答案(最好是工作示例代码).干杯,祝你好运!

下面的部分解决方案(工作但不是最佳):

下面是我提出的代码,它是嵌入式资源上这个链接的技术(由Otaku建议)和我自己的Prism模块目录的迭代.

  • 问题1 - 所有模块都已加载,因此基本上必须再次下载它们,因为我无法解决如何迭代所有当前加载的Prism模块.如果有人想在这个上分享赏金,你仍然可以帮助这个成为一个完整的解决方案!

  • 问题2 - ResourceManager中显然存在一个错误,它要求您获取已知资源的流,然后才能迭代所有资源项(请参阅下面的代码中的注释).这意味着我必须在每个模块中都有一个虚拟资源文件.很高兴知道为什么需要初始的GetStream调用(或者如何避免它).

    private void ParseAllXamlInAllModules()
    {
        IModuleCatalog mm = this.UnityContainer.Resolve<IModuleCatalog>();
        foreach (var module in mm.Modules)
        {
            string xap = module.Ref;
            WebClient wc = new WebClient();
            wc.OpenReadCompleted += (s, args) =>
            {
                if (args.Error == null)
                {
                    var resourceInfo = new StreamResourceInfo(args.Result, null);
                    var file = new Uri("AppManifest.xaml", UriKind.Relative);
                    var stream = System.Windows.Application.GetResourceStream(resourceInfo, file);
                    XmlReader reader = XmlReader.Create(stream.Stream);
                    var parts = new AssemblyPartCollection();
                    if (reader.Read())
                    {
                        reader.ReadStartElement();
                        if (reader.ReadToNextSibling("Deployment.Parts"))
                        {
                            while (reader.ReadToFollowing("AssemblyPart"))
                            {
                                parts.Add(new AssemblyPart() { Source = reader.GetAttribute("Source") });
                            }
                        }
                    }
                    foreach (var part in parts)
                    {
                        var info = new StreamResourceInfo(args.Result, null);
                        Assembly assy = part.Load(System.Windows.Application.GetResourceStream(info, new Uri(part.Source, UriKind.Relative)).Stream);
                        // Get embedded resource names
                        string[] resources = assy.GetManifestResourceNames();
                        foreach (var resource in resources)
                        {
                            if (!resource.Contains("DummyResource.xaml"))
                            {
                                // to get the actual values - create the table
                                var table = new Dictionary<string, Stream>();
                                // All resources have “.resources” in the name – so remove it
                                var rm = new ResourceManager(resource.Replace(".resources", String.Empty), assy);
                                // Seems like some issue here, but without getting any real stream next statement doesn't work....
                                var dummy = rm.GetStream("DummyResource.xaml");
                                var rs = rm.GetResourceSet(Thread.CurrentThread.CurrentUICulture, false, true);
                                IDictionaryEnumerator enumerator = rs.GetEnumerator();
                                while (enumerator.MoveNext())
                                {
                                    if (enumerator.Key.ToString().EndsWith(".xaml"))
                                    {
                                        table.Add(enumerator.Key.ToString(), enumerator.Value as Stream);
                                    }
                                }
                                foreach (var xaml in table)
                                {
                                    TextReader xamlreader = new StreamReader(xaml.Value);
                                    string content = xamlreader.ReadToEnd();
                                    {
                                        // This is where I do the actual work on the XAML content
                                    }
                                }
                            }
                        }
                    }
                }
            };
            // Do the actual read to trigger the above callback code
            wc.OpenReadAsync(new Uri(xap, UriKind.RelativeOrAbsolute));
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

Tod*_*ain 5

使用GetManifestResourceNames反射和解析从那里只获得以.xaml结尾的那些.以下是使用的示例GetManifestResourceNames:枚举嵌入式资源.虽然示例显示了如何使用单独的.xap执行此操作,但您可以使用加载的.xap执行此操作.