我开始实现this tutorial中的MEF示例代码,该代码描述了为元数据创建自定义ExportAttribute属性.在我尝试在元数据中包含资源文件中的图像之前,一切都在顺利进行.目标是将每个插件DLL的标题,描述和图标提取为元数据,以便在主程序中构建插件菜单.
我现在得到编译错误:
“An attribute argument must be a constant expression,typeof expression
or array creation expression of an attribute parameter type”
1)如何在属性中包含图像?
要么
2)如何在不使用属性的情况下在MEF中包含元数据?
这是我正在使用的代码:
在合同类中:
// Metadata contract interface public interface IPlugInMetadata { string PlugInTitle { get; } string PlugInDescription { get; } Image PlugInIcon { get; } } // Plug-In contract interface public interface IPlugIn { void StartPlugIn(object systemObject); void StopPlugin(); }
[MetadataAttribute] [AttributeUsage(AttributeTargets.Class,AllowMultiple = false)] public class PluginMetadataAttribute : ExportAttribute { public string title { get; set; } public string description { get; set; } public Image icon { get; set; } public PluginMetadataAttribute(string plugInTitle,string plugInDescription,Image plugInIcon) : base(typeof(IPlugInMetadata)) { title = plugInTitle; description = plugInDescription; icon = plugInIcon; } }
最后,Plug-In DLL中的Program类:
[Export(typeof(IPlugIn))] [PluginMetadata(ResourceFile.PlugInTitle,ResourceFile.PlugInDescription,ResourceFile.PlugInIcon24)] public class Program : IPlugIn { public void StartPlugIn(object systemObject) { Console.WriteLine("Start Plug-In: " + ResourceFile.PlugInTitle); } public void StopPlugin() { Console.WriteLine("Stop Plug-In: " + ResourceFile.PlugInTitle); } }
这条线产生错误.
[PluginMetadata(ResourceFile.PlugInTitle,ResourceFile.PlugInIcon24)]
显然,ResourceFile不被视为常量,但是我如何将图像用作元数据,或者这是不可能的? (请注意,图像设置为“嵌入.resx”)
感谢您的任何帮助或建议!
解决方法
好的,据我所知,你不能在MEF元数据中使用图像或图标.但是,您可以为DLL文件指定一个图标,就像为EXE文件一样.然后可以使用.NET类型中内置的静态方法读取图标:
Icon MyDLLIcon = Icon.ExtractAssociatedIcon(DLLFilePath);
我仍然不确定为什么你可以将资源文件中的字符串作为MEF元数据返回,而不是嵌入的图标或图像.
由于我一直试图拼凑一个功能性的示例程序,该程序现在提供带有图标的插件菜单几天,我想我会发布代码,以防它帮助其他任何人.
>旨在成为包含5个项目的单一解决方案(MainProgram,ContractInterfaces,PlugInA,PlugInB,PlugInC)
> Post Build Events将自动将每个项目的DLL复制到一个常见的“Plug-Ins”文件夹中
> MainProgram(WinForm)项目将构建可用DLL插件的目录,并使用每个插件的图标和元数据标题填充ListView
>双击ListView项将实例化插件(利用Lazy实例化),然后启动它.
>每个插件将在启动时接收对主窗体的引用,创建一个新的TextBox,并将其发布到主窗体以证明它已运行并可以访问GUI.
>所选插件的标题,描述和版本元数据值将打印到控制台窗口
我为每个DLL分配了一个不同的Icon(来自旧的Visual Studio 6 Common Graphics Misc文件夹)
从DLL插件中提取图标以创建ListView,并且一旦它们启动(在双击ListView中的每个插件项之后),DLL就会创建文档框并将其发布到GUI.
将以下代码添加到名为“MainProgram”的全新C#WinForm项目中(我使用的是VS 2010):
由于某种原因,Code Sample解析器不喜欢Using语句,因此它们作为要点:
>使用系统;
>使用System.Collections.Generic;
>使用System.ComponentModel.Composition;
>使用System.ComponentModel.Composition.Hosting;
>使用System.Drawing;
>使用System.IO;
>使用System.Windows.Forms;
>使用ContractInterfaces;
>(命名空间)MainProgram
public partial class Form1 : Form { // Prerequisites to run: // 1) Project,Add Reference,Projects,ContractInterface // 2) Project,.NET,System.ComponentModel.Composition [ImportMany(typeof(IPlugIn))] private IEnumerable<Lazy<IPlugIn,IPlugInMetadata>> LoadedplugIns; List<PlugInInfo> AvailablePlugIns = null; public Form1() { InitializeComponent(); } private void Form1_Load(object sender,EventArgs e) { // Get a list of the available Plug-Ins AvailablePlugIns = GetPlugInList(); // Prepare an ImageList to hold the DLL icons ImageList ImgList = new ImageList(); ImgList.ColorDepth = ColorDepth.Depth32Bit; ImgList.ImageSize = new Size(32,32); // Populate ImageList with Plug-In Icons foreach (var item in AvailablePlugIns) { ImgList.Images.Add(item.PlugInIcon.ToBitmap()); } // Assign the ImageList to the ListView listView1.LargeImageList = ImgList; int imageIndex = 0; // Create the ListView items foreach (var item in AvailablePlugIns) { listView1.Items.Add(item.PlugInTitle,imageIndex); imageIndex++; } listView1.MouseDoubleClick += new MouseEventHandler(listView1_MouseDoubleClick); } void listView1_MouseDoubleClick(object sender,MouseEventArgs e) { // Get the Plug-In index number int plugInNum = listView1.SelectedItems[0].Index; PlugInInfo selectedplugIn = AvailablePlugIns[plugInNum]; // Call the StartPlugIn method in the selected Plug-In. // Lazy Instantiation will fully load the Assembly here selectedplugIn.PlugIn.StartPlugIn(this); Console.WriteLine("Plug-In Title: {0}",selectedplugIn.PlugInTitle); Console.WriteLine("Plug-In Description: {0}",selectedplugIn.PlugInDescription); Console.WriteLine("Plug-In Version: {0}",selectedplugIn.PlugInVersion); Console.WriteLine(); } private List<PlugInInfo> GetPlugInList() { // Create a List to hold the info for each plug-in List<PlugInInfo> plugInList = new List<PlugInInfo>(); // Set Plug-In folder path to same directory level as Solution string plugInFolderPath = System.IO.Path.Combine(Application.StartupPath,@"..\..\..\Plug-Ins"); // Test if the Plug-In folder exists if (!Directory.Exists(plugInFolderPath)) { // Plug-In Folder is missing,so try to create it try { Directory.CreateDirectory(plugInFolderPath); } catch { MessageBox.Show("Failed to create Plug-In folder","Folder Creation Error:",MessageBoxButtons.OK,MessageBoxIcon.Exclamation); } } try { // Create a catalog of plug-ins var catalog = new DirectoryCatalog(plugInFolderPath,"*.dll"); AggregateCatalog plugInCatalog = new AggregateCatalog(); plugInCatalog.Catalogs.Add(catalog); CompositionContainer container = new CompositionContainer(plugInCatalog); // This line will fetch the Metadata from each plug-in and populate LoadedplugIns container.ComposeParts(this); // Save each Plug-Ins Metadata foreach (var plugin in LoadedplugIns) { PlugInInfo info = new PlugInInfo(); info.PlugInTitle = plugin.Metadata.PlugInTitle; info.PlugInDescription = plugin.Metadata.PlugInDescription; info.PlugInVersion = plugin.Metadata.PlugInVersion; info.PlugIn = plugin.Value; plugInList.Add(info); } int index = 0; // Extract icons from each Plug-In DLL and store in Plug-In list foreach (var filePath in catalog.LoadedFiles) { plugInList[index].PlugInIcon = Icon.ExtractAssociatedIcon(filePath); index++; } } catch (FileNotFoundException fex) { Console.WriteLine("File not found exception : " + fex.Message); } catch (CompositionException cex) { Console.WriteLine("Composition exception : " + cex.Message); } catch (DirectoryNotFoundException dex) { Console.WriteLine("Directory not found exception : " + dex.Message); } return plugInList; } } public class PlugInInfo { public string PlugInTitle { get; set; } public string PlugInDescription { get; set; } public string PlugInVersion { get; set; } public Icon PlugInIcon { get; set; } public IPlugIn PlugIn { get; set; } }
现在将一个名为“listView1”的ListView控件添加到主窗体,并将其保存到窗体的右侧.插件中动态创建的TextBox将显示在左侧.
接下来添加一个名为“ContractInterfaces”的类项目,然后包含以下代码:
>使用System.Windows.Forms;
>(namespace)ContractInterfaces
// Prerequisites to run: // 1) Project,"System.Windows.Forms" public interface IPlugIn { void StartPlugIn(Form mainForm); } public interface IPlugInMetadata { string PlugInTitle { get; } string PlugInDescription { get; } string PlugInVersion { get; } }
接下来添加一个名为“PlugInA”的类项目,然后包含以下代码:
>使用系统;
>使用System.ComponentModel.Composition;
>使用System.Windows.Forms;
>使用ContractInterfaces;
>(名称空间)PlugInA
// Prerequisites to run: // 1) Project,"ContractInterface" // 2) Project,"System.Windows.Forms" // 3) Project,"System.ComponentModel.Composition" // 4) Project,Properties,Build Events,Post-Build event command line: // xcopy "$(ProjectDir)$(OutDir)$(TargetFileName)" "$(SolutionDir)Plug-Ins\" /Y // 5) Project,Run the post-build event:,Always // 6) Project,Application,Icon and manifest,[Select an icon] [Export(typeof(IPlugIn))] [PluginMetadata] public class Program : IPlugIn { private Form MainForm; public void StartPlugIn(Form mainForm) { MainForm = mainForm; // Place a TextBox on the Main Form TextBox textBox = new TextBox(); textBox.Text = "PlugInA"; MainForm.Controls.Add(textBox); textBox.Width = 65; textBox.Height = 20; textBox.Top = 0; textBox.Left = 0; } } // Create a custom strong-typed Metadata Attribute for MEF [MetadataAttribute] [AttributeUsage(AttributeTargets.Class,AllowMultiple = false)] public class PluginMetadataAttribute : ExportAttribute { public string PlugInTitle { get; set; } public string PlugInDescription { get; set; } public object PlugInVersion { get; set; } public PluginMetadataAttribute() : base(typeof(IPlugInMetadata)) { PlugInTitle = "Plug-In A"; PlugInDescription = "This is Plug-In A"; PlugInVersion = "1.0.0.0"; } }
接下来添加一个名为“PlugInB”的类项目,然后包含以下代码:
>使用系统;
>使用System.ComponentModel.Composition;
>使用System.Windows.Forms;
>使用ContractInterfaces;
>(名称空间)PlugInB
// Prerequisites to run: // 1) Project,[Select an icon] [Export(typeof(IPlugIn))] [PluginMetadata] public class Program : IPlugIn { private Form MainForm; public void StartPlugIn(Form mainForm) { MainForm = mainForm; // Place a TextBox on the Main Form TextBox textBox = new TextBox(); textBox.Text = "PlugInB"; MainForm.Controls.Add(textBox); textBox.Width = 65; textBox.Height = 20; textBox.Top = 30; textBox.Left = 0; } } // Create a custom strong-typed Metadata Attribute for MEF [MetadataAttribute] [AttributeUsage(AttributeTargets.Class,AllowMultiple = false)] public class PluginMetadataAttribute : ExportAttribute { public string PlugInTitle { get; set; } public string PlugInDescription { get; set; } public object PlugInVersion { get; set; } public PluginMetadataAttribute() : base(typeof(IPlugInMetadata)) { PlugInTitle = "Plug-In B"; PlugInDescription = "This is Plug-In B"; PlugInVersion = "1.0.0.1"; } }
接下来添加一个名为“PlugInC”的类项目,然后包含以下代码:
>使用系统;
>使用System.ComponentModel.Composition;
>使用System.Windows.Forms;
>使用ContractInterfaces;
>(命名空间)PlugInC
// Prerequisites to run: // 1) Project,[Select an icon] [Export(typeof(IPlugIn))] [PluginMetadata] public class Program : IPlugIn { private Form MainForm; public void StartPlugIn(Form mainForm) { MainForm = mainForm; // Place a TextBox on the Main Form TextBox textBox = new TextBox(); textBox.Text = "PlugInC"; MainForm.Controls.Add(textBox); textBox.Width = 65; textBox.Height = 20; textBox.Top = 60; textBox.Left = 0; } } // Create a custom strong-typed Metadata Attribute for MEF [MetadataAttribute] [AttributeUsage(AttributeTargets.Class,AllowMultiple = false)] public class PluginMetadataAttribute : ExportAttribute { public string PlugInTitle { get; set; } public string PlugInDescription { get; set; } public object PlugInVersion { get; set; } public PluginMetadataAttribute() : base(typeof(IPlugInMetadata)) { PlugInTitle = "Plug-In C"; PlugInDescription = "This is Plug-In C"; PlugInVersion = "1.0.0.2"; } }
解决方案应如下所示:
右键单击Solution,然后选择“Project Dependencies …”.设置依赖项如下:
> MainProgram – 取决于 – ContractInterface
> PlugInA – 取决于 – ContractInterface
> PlugInB – 取决于 – ContractInterface
> PlugInC – 取决于 – ContractInterface
> ContractInterface – 取决于 – [没有]
右键单击解决方案,然后选择“项目构建顺序…”.构建顺序应如下所示:
> ContractInterface
> PlugInA
> PlugInB
> PlugInC
> MainProgram
构建并运行该程序.您应该看到3个DLL文件被复制到与解决方案文件(* .sln)相同的目录级别的新“Plug-Ins”文件夹中.如果没有,请检查项目构建顺序,依赖项,以及您是否根据上面插件代码中的注释输入了构建后事件.如果文件在那里,则应在带有插件条目的表单中填充ListView.双击每个ListView条目以启动插件.
玩得开心,我希望这有助于某人….
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。