企业网站策划建设方案,网页设计模板的网站,装饰画图片大全,虚拟机中建设iis网站Chris SellsSells Brothers Consulting 摘要#xff1a;Chris Sells 讨论无类型清单资源和有类型资源#xff0c;它们是受 Microsoft .NET 框架支持的两种资源。他定义了这两种资源#xff0c;并介绍了如何在您自己的应用程序中使用它们。 下载 winforms02202003.exe 示例文…Chris SellsSells Brothers Consulting 摘要Chris Sells 讨论无类型清单资源和有类型资源它们是受 Microsoft .NET 框架支持的两种资源。他定义了这两种资源并介绍了如何在您自己的应用程序中使用它们。 下载 winforms02202003.exe 示例文件。 假设要在应用程序中通过从文件加载位图来设置窗体的背景图像public Form1() {...// Load a file from the file systemthis.BackgroundImage new Bitmap(C:\WINDOWS\Web\Wallpaper\Azul.jpg);
}该代码的问题是并非所有 Microsoft Windows 的安装实例都有 Azul.jpg即使是那些确实具有该文件的安装实例该文件可能也不在安装实例的相同位置。即使您与应用程序一起交付该图片节省空间的用户也可能决定删除它这会导致您的应用程序出错。确保图片或任何文件与代码在一起的唯一安全方式是将它作为资源嵌入并加载。 清单资源 资源是在编译时添加到程序集中的。例如如果您使用命令行编译器则可以使用 /resource 开关嵌入资源C:\csc.exe myApp.cs /resource:c:\windows\web\wallpaper\Azul.jpg/resource 开关将文件作为资源嵌入嵌入时使用文件名没有路径作为资源名称。文件嵌入到程序集的清单 资源集中。程序集的清单由一组作为程序集一部分的元数据组成。该元数据的一部分是与每个嵌入资源关联的名称和数据。执行 ildasm 时可以在清单部分看见程序集清单资源的列表如图 1 所示。C:\ildasm.exe myApp.exe图 1. ildasm 显示嵌入资源 可以像 ildasm 一样枚举清单资源的列表这需要使用 System.Reflection.Assembly 类的 GetManifestResourceNames 方法using System.Reflection;
...
// Get this types assembly
Assembly assem this.GetType().Assembly;// Enumerate the assemblys manifest resources
foreach( string resourceName in assem.GetManifestResourceNames() ) {MessageBox.Show(resourceName);
}一旦通过枚举清单资源或硬编码一个您想要的清单资源而知道了清单资源的名称就可以通过 Assembly 类的 GetManifestResourceStream 方法将该清单资源作为原始字节流进行加载如下所示using System.IO;public Form1() {...// Get this types assemblyAssembly assem this.GetType().Assembly;// Get the stream that holds the resource// NOTE1: Make sure not to close this stream!// NOTE2: Also be very careful to match the case// on the resource name itselfStream stream assem.GetManifestResourceStream(Azul.jpg);// Load the bitmap from the streamthis.BackgroundImage new Bitmap(stream);
}因为资源可以像类型名称一样有冲突所以最好用资源自己的“命名空间”来嵌入资源该操作可以使用 /resource 开关的扩展格式来完成C:\csc myApp.cs /resource:c:\...\azul.jpg,ResourcesApp.Azul.jpg注意在要嵌入的文件名的逗号后面使用的备用资源名称。备用资源名称允许您为资源任意地提供时间嵌套名称不管文件名是什么。它是设置在程序集中的备用名称如图 2 所示。 图 2. 使用备用名称的嵌入资源 下面是使用备用名称的更新后的资源加载代码public Form1() {...// Get this types assemblyAssembly assem this.GetType().Assembly;// Load a resource with an alternate nameStream stream assem.GetManifestResourceStream(ResourcesApp.Azul.jpg);// Load the bitmap from the streamthis.BackgroundImage new Bitmap(stream);
}为了更方便如果您的资源和加载资源的类碰巧使用了相同的命名空间则可以将类的类型作为可选的第一参数传递给 GetManifestResourceStreamnamespace ResourcesApp {public class Form1 : Form {public Form1() {...// Get this types assemblyAssembly assem this.GetType().Assembly;// Load the resource using a namespace// Will load resource named ResourcesApp.Azul.jpgStream stream assem.GetManifestResourceStream(this.GetType(), Azul.jpg);// Load the bitmap from the streamthis.BackgroundImage new Bitmap(stream);}...}
}GetManifestResourceStream 将使用如下格式编写资源名称namespace.fileName在加载某些类型比如 Bitmap 类时使用类型和文件名也是有用的这样可以通过提供构造函数避免由您自己打开流 namespace ResourcesApp { public class Form1 : Form { public Form1() { ... // Get this types assembly Assembly assem this.GetType().Assembly; // Load the bitmap directly from the manifest resources this.BackgroundImage new Bitmap(this.GetType(), Azul.jpg); } ... }} Visual Studio .NET 中的清单资源 如果大多数情况下您使用 Visual Studio?NET 来开发和构建程序集则用命令行嵌入清单资源的方法不可能非常吸引您。这种情况下您可以将资源添加到 Windows 窗体项目中该方法将把合适的命令行参数传递给编译器。 要将资源添加到项目中请在 Solution Explorer 中右键单击项目然后选择 Add New Item并选择您想作为资源嵌入的文件。文件将复制到项目的目录中但仍然不会被嵌入。要使文件作为资源嵌入请右键单击文件并选择 Properties然后将 Build Action 从 Content默认更改为 Embedded Resource如图 3 所示。 图 3. 将文件的 Build Action 设置为 Embedded Resource 这种嵌入资源的方法会使 Visual Studio .NET 为您创建一个备用资源名其组成类似这样defaultNamespace.folderName.fileName 资源名称的默认命名空间部分是项目本身的默认命名空间它是通过 Solution Explorer-右键单击-Properties-Common Properties-General-Default Namespace 来设置的。由于这是在生成新类时新类得到的相同命名空间所以这就使通过使用类型和部分资源名称来加载资源变得很方便。如果文件碰巧位于项目的子文件夹中就需要在文件夹名称中包括子文件夹并用点替换反斜杠。例如一个名为 Azul.jpg 的位图位于项目根下面的 foo\bar 文件夹中要加载它就需要这样做// If this code called within the ResourcesApp.Form1 class,
// and the file is \foo\bar\Azul.jpg,
// will load ResourcesApp.foo.bar.Azul.jpg
this.BackgroundImage new Bitmap(this.GetType(), foo.bar.Azul.jpg);有类型资源 尽管文件有扩展名但清单资源是在没有类型信息的情况下嵌入的。例如如果 Azul.jpg 文件的名称实际上是 Azul.quux这对于 Bitmap 类来说是没有差别的因为这个类将通过查看数据本身来确定其类型JPEG、PNG、GIF 等。这就需要由您来将每个资源的类型正确映射为加载该资源所需的对象的类型。 但如果您愿意多走一步则可以用一个类型来标记资源。.NET 框架支持用于资源的一组扩展元数据其中包括两种格式的 MIME 类型信息一个是文本格式另一个是二进制格式。这两种格式都有内置的读取器以便在运行时取得类型正确的资源。 基于文本的格式是特定于.NET 框架的 XML 格式称为 ResX.resx 文件。不考虑其 XML 基础该格式不是专门为人工阅读而设计的XML 格式很少是这样的。但是Visual Studio .NET 仍然为 .resx 文件提供了一个基本编辑器。要将新的 .resx 文件添加到 Visual Studio .NET 项目中请从 Project 菜单中选择 Add New Item然后选择 Assembly Resource File 模板如图 4 所示。 图 4. 将 .resx 文件添加到项目中 到写本文时为止即使空的 .resx 文件也是 42 行 XML而其中大多数是架构信息。架构允许 .resx 文件中有任意数目的项每项都有名称、值、注释、类型和 MIME 类型。图 5 显示了有两个项的 .resx 文件即名为 MyString 的字符串和名为 MyImage 的图像。 图 5. 设计器的数据视图中简单的 .resx 文件 遗憾的是只有字符串项能够在 .resx 编辑器的数据视图中实际进行编辑。任何二进制数据都需要手动直接输入到 XML 中而且只能是 base64 编码。因此直接使用 .resx 文件只对字符串资源有用尽管间接使用会使 .resx 文件对任何种类的数据都非常有用我们随后将讨论这一点。 来自 System.Resources 命名空间的 ResXResourceReader 类将分析 XML 文件并公开一组命名的、有类型的值。要取得具体的项需要查找它using System.Collections;
using System.Resources;
...
public Form1() {...using( ResXResourceReader reader new ResXResourceReader(Resource1.resx) ) {foreach( DictionaryEntry entry in reader ) {if( entry.Key.ToString() MyString ) {// Set form caption from string resourcethis.Text entry.Value.ToString();}}}
}使用 Add New Item 对话框将 .resx 文件添加到项目中会使该文件作为 Embedded Resource 添加进项目而编译项目时则会导致 .resx 数据作为嵌套资源 嵌入“嵌套资源”是分组到命名容器中的资源。容器的名称与作为资源添加的任何文件相同只是不使用 .resx 扩展名使用 .resource 扩展名。假定一个项目的默认命名空间是 ResourcesApp 而 .resx 文件名为 Resources1.resx则嵌套资源的容器名为 ResourcesApp.Resources1.resx如图 6 中的 ildasm 所示。 图 6. 嵌入的 .resources 文件 .resources 扩展名来自于在将 .resx 文件作为资源嵌入之前 Visual Studio .NET 处理该文件时所使用的工具。工具名称是 resgen.exe它用来将 .resx XML 格式“编译”为二进制格式。可以手动将 .resx 文件编译成 .resources 文件如下所示C:\ resgen.exe Resource1.resx在将 .resx 文件编译成 .resources 文件以后就可以使用 System.Resources 命名空间中的 ResourceReader 来枚举它using( ResourceReader reader new ResourceReader(Resource1.resources) ) {foreach( DictionaryEntry entry in reader ) {string s string.Format({0} ({1}) {2},entry.Key, entry.Value.GetType(), entry.Value);MessageBox.Show(s);}
}除了类的名称和输入格式ResourceReader 类的使用方法与 ResXResourceReader 相同包括都不能随机访问命名项。 所以虽然您可以将 .resx 文件转换成 .resources 文件并使用 /resource 编译器命令行开关嵌入它但容易得多的方法是直接在项目中让 Visual Studio .NET 接受被标记为 Embedded Resources 的 .resx 文件然后将它编译进 .resources 文件并嵌入它如图 4、图 5 和图 6 所示。一旦将 .resources 文件捆绑为资源访问 .resources 文件中的资源就只需执行两个步骤的过程// 1. Load embedded .resources file
using( Stream stream assem.GetManifestResourceStream(this.GetType(), Resource1.resources) ) {// 2. Find resource in .resources fileusing( ResourceReader reader new ResourceReader(stream) ) {foreach( DictionaryEntry entry in reader ) {if( entry.Key.ToString() MyString ) {// Set form caption from string resourcethis.Text entry.Value.ToString();}}}
}因为 ResourceReader 和 ResXResourceReader 都需要该两步过程才能找到具体的资源因此 .NET 框架提供了 ResourceManager 类该类公开了一个更简单的使用模型。 资源管理器ResourceManager 类也来自 System.Resources 命名空间该类包装了 ResourceReader用于在构造时枚举资源并使用其名称公开它们
public Form1() {...// Get this types assemblyAssembly assem this.GetType().Assembly;// Load the .resources file into the ResourceManager// Assumes a file named Resource1.resx as part of the projectResourceManager resman new ResourceManager(ResourcesApp.Resource1, assem);// Set form caption from string resourcethis.Text (string)resman.GetObject(MyString); // The hard waythis.Text resman.GetString(MyString); // The easy way
}用来查找 .resources 文件的命名方式与命名任何其他种类的资源相同注意追加到 Resource1.resources 文件中的项目默认命名空间的使用方法只是 .resources 扩展名是假定的并且不能包括在名称中。为了更方便如果您碰巧将一个 .resx 文件命名为类型名称则 .resources 文件和程序集的名称将从类型确定// Use the type to determine resource name and assembly
ResourceManager resman new ResourceManager(this.GetType());一旦已经创建了资源管理器的实例就可以通过使用 GetObject 方法并强制转换为合适的类型从而按名称找到嵌套资源。如果使用 .resx 文件来处理字符串资源则可以使用 GetString 方法该方法将执行到 System.String 类型的强制转换。 设计器资源 缺少用于 .resx 文件的合适的编辑器使它们在使用除字符串资源以外的任何其他资源时非常困难。您不仅必须通过手动编写代码才能在运行时输入数据而且无法在设计时看见资源的使用情况例如窗体的背景图像。 幸运的是设计器再次在这里帮助了我们。如果打开 Visual Studio .NET Solution Explorer并选择 Show All Files 按钮您将看见每个组件无论它是窗体、控件还是简单的组件都有相应的 .resx 文件。这是为了让资源与组件的属性保持关联这种关联是在 Property Browser 中设置的。例如如果设置窗体的 BackgroundImage 属性那么不仅在设计器中窗体将显示背景图像而且窗体的 .resx 文件将包含该图像的对应项。同样如果在相同窗体上设置 PictureBox 控件的 Image 属性则 .resx 文件同样会增大以便包括该资源。这两项都可以在图 7 中看到。 图 7. 组件的 .resx 文件 每个组件的 .resx 文件将作为 .resources 文件进行编译和嵌入就像已经将您自己的 .resx 文件添加到项目中一样这将使资源能够在运行时被组件使用。除了组件的 .resx 文件中的项之外设计器还会将代码添加到 InitializeComponent 中以便加载组件的资源管理器并使用从资源获得的对象来填充组件的属性namespace ResourcesApp {public class Form1 : Form {...private void InitializeComponent() {ResourceManager resources new ResourceManager(typeof(Form1));...this.pictureBox1.Image (System.Drawing.Bitmap)resources.GetObject(pictureBox1.Image);...this.BackgroundImage (System.Drawing.Bitmap)resources.GetObject($this.BackgroundImage);...}}
}注意 ResourceManager 对象是使用组件的类型来构造的该类型用来构造组件的 .resources 资源名称。还要注意设计器在命名资源时所使用的命名约定。对于组件字段上的属性名称的格式是fieldName.propertyName对于组件本身的属性名称格式是$this.propertyName如果您想添加供组件本身使用的自定义字符串属性您可以这样做但要确保与设计器生成的名称格式不同。 我们所处的位置 Microsoft .NET 框架支持两种资源 — 无类型清单资源和有类型资源。通过将文件的 Build Action 设置为 Embedded Resource可以让 Visual Studio .NET 支持无类型清单资源并通过 .resx 文件可以是自定义文件或作为组件资源的备份存储支持有类型资源。清单资源的好处是它们可在 IDE 中直接编辑而有类型资源需要做特别的工作才能编辑但可提供有类型访问。两种资源类型都有某些严格的命名要求所以在编写方法调用来加载它们时要格外小心。转载于:https://www.cnblogs.com/newsun/archive/2007/12/28/1018539.html