【发布时间】:2011-04-10 07:16:00
【问题描述】:
有没有一种简单的方法可以动态发现所有当前加载的模块(特别是 Silverlight Prism 应用程序)中的所有 XAML 文件?我相信这是可能的,但不确定从哪里开始.
这必须发生在 Silverlight 客户端上:我们当然可以在开发机器上解析项目,但这会降低灵活性并且会在搜索中包含未使用的文件。
基本上,我们希望能够解析非常大的 Prism 项目中的所有 XAML 文件(独立于加载它们)以识别所有本地化字符串。这将让我们建立一个初始本地化数据库,其中包括我们所有的资源绑定字符串,并创建一个查找它们出现在哪些 XAML 文件中(以便于翻译人员进行编辑)。
为什么要这样做?:对于翻译人员来说,最糟糕的事情是在一个上下文中更改一个字符串,却发现它在其他地方使用的含义略有不同。我们正在启用上下文中的翻译编辑在应用程序本身内。
更新(9 月 14 日):
由于安全限制,Silverlight 无法使用迭代程序集的标准方法。这意味着对以下解决方案的唯一改进是在可能的情况下与 Prism 模块管理合作。如果有人想为这个问题的最后一部分提供代码解决方案,可以与您分享一些要点!
跟进:
由于各种原因,在基于模块的项目中迭代 XAP 文件的内容似乎是一件非常方便的事情,因此再增加 100 个代表以获得真正的答案(最好是工作示例代码)。干杯,祝你好运!
下面的部分解决方案(工作但不是最佳):
下面是我想出的代码,它是来自this link on Embedded resources(由 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)); } }
【问题讨论】:
标签: silverlight xaml mvvm prism