如何动态发现 Silverlight 棱镜应用程序中所有模块中的所有 XAML 文件 [英] How to dynamically discover all XAML files in all modules in a Silverlight prism app

查看:35
本文介绍了如何动态发现 Silverlight 棱镜应用程序中所有模块中的所有 XAML 文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is there an easy way to dynamically discover all the XAMLs files within all the currently loaded modules (specifically of a Silverlight Prism application)? I am sure this is possible, but not sure where to start.

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

This has to occur on the Silverlight client: We could of course parse the projects on the dev machine, but that would reduce the flexibility and would include unused files in the search.

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

Basically we want to be able to parse all XAML files in a very large Prism project (independent of loading them) to identify all localisation strings. This will let us build up an initial localisation database that includes all our resource-binding strings and also create a lookup of which XAML files they occur in (to make editing easy for translators).

为什么要这样做?:对于翻译人员来说,最糟糕的事情是在一个上下文中更改字符串,却发现它在其他地方使用的含义略有不同.我们正在启用对来自以下内容的翻译的上下文编辑在应用程序本身内.

Why do this?: The worst thing for translators is to change a string in one context only to find it was used elsewhere with slightly different meaning. We are enabling in-context editing of translations from within the application itself.

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

The standard method for iterating assemblies is not available to Silverlight due to security restrictions. This means the only improvement to the solution below would be to cooperate with the Prism module management if possible. If anyone wants to provide a code solution for that last part of this problem there are points available to share with you!

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

Iterating content of XAP files in a module-base project seems like a really handy thing to be able to do for various reasons, so putting up another 100 rep to get a real answer (preferably working example code). Cheers and good luck!

下面是我想出的代码,它是来自 这个关于嵌入式资源的链接(由 Otaku 建议)和我自己对 Prism 模块目录的迭代.

Below is the code I have come up with, which is a paste together of techniques from this link on Embedded resources (as suggested by Otaku) and my own iterating of the Prism Module Catalogue.

  • 问题 1 - 所有模块都是已经加载所以这基本上是必须一秒钟全部下载时间,因为我不知道如何迭代所有当前加载的 Prism 模块.如果有人想分享赏金在这一点上,你仍然可以帮助制作这是一个完整的解决方案!

  • Problem 1 - all the modules are already loaded so this is basically having to download them all a second time as I can't work out how to iterate all currently loaded Prism modules. If anyone wants to share the bounty on this one, you still can help make this a complete solution!

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

Problem 2 - There is apparently a bug in the ResourceManager that requires you to get the stream of a known resource before it will let you iterate all resource items (see note in the code below). This means I have to have a dummy resource file in every module. It would be nice to know why that initial GetStream call is required (or how to avoid it).

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));
    }
}

推荐答案

使用 GetManifestResourceNames 反射并从那里解析以仅获取以 .xaml 结尾的那些.以下是使用 GetManifestResourceNames 的示例:枚举嵌入的资源.尽管示例展示了如何使用单独的 .xap 执行此操作,但您可以使用已加载的文件执行此操作.

Use GetManifestResourceNames reflection and parse from there to get only those ending with .xaml. Here's an example of using GetManifestResourceNames: Enumerating embedded resources. Although the sample is showing how to do this with a seperate .xap, you can do this with the loaded one.

这篇关于如何动态发现 Silverlight 棱镜应用程序中所有模块中的所有 XAML 文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆