gpt4 book ai didi

c# - 如何使用 MEF 在插件 DLL 的元数据中包含图像?

转载 作者:太空狗 更新时间:2023-10-29 23:32:42 25 4
gpt4 key购买 nike

C# .NET 4.0 WinForms

我从 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();
}

插件 DLL 中的自定义属性:
[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;
}
}

最后,插件 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.PlugInDescription, ResourceFile.PlugInIcon24)]

显然 ResourceFile 不被视为常量,但是我如何将图像用作元数据,或者这是不可能的? (请注意,图像设置为“嵌入 .resx”)

感谢您的任何帮助或建议!

最佳答案

找到了解决办法:

好吧,据我所知,您不能在 MEF 元数据中使用图像或图标。但是,您可以为 DLL 文件指定一个图标,就像为 EXE 文件所做的那样。然后可以使用内置于 .NET 图标类型中的静态方法读取图标:

Icon MyDLLIcon = Icon.ExtractAssociatedIcon(DLLFilePath);

我仍然不确定为什么可以从资源文件中返回字符串作为 MEF 元数据,而不是嵌入的图标或图像。

由于几天来我一直在尝试拼凑一个功能强大的示例程序,该程序提供带有图标的插件菜单,因此我想我会发布代码以帮助其他人。

这是一个功能齐全的示例项目,具有以下功能:
  • 旨在成为具有 5 个项目( MainProgram、ContractInterfaces、PlugInA、PlugInB、PlugInC)的单一解决方案
  • Post Build Events 会自动将每个项目中的 DLL 复制到一个公共(public)的“插件”文件夹
  • MainProgram (WinForm) 项目将构建可用 DLL 插件的目录,并使用每个插件的图标和元数据标题填充 ListView
  • 双击 ListView 项将实例化插件(利用延迟实例化),并启动它。
  • 每个 Plug-In 在启动时都会收到对主 Form 的引用,创建一个新的 TextBox,并将其发布到主 Form 以证明它可以运行并可以访问 GUI。
  • 所选插件的标题、描述和版本元数据值将打印到控制台窗口


  • 我为每个 DLL 分配了一个不同的图标(来自旧的 Visual Studio 6 Common Graphics Misc 文件夹)

    Screenshot

    从 DLL 插件中提取图标以创建 ListView,并且文本框由 DLL 创建并在它们启动后发布到 GUI(在双击 ListView 中的每个插件项之后)。

    将以下代码添加到名为“MainProgram”的全新 C# WinForm 项目(我使用 VS 2010):

    出于某种原因,代码示例解析器不喜欢 Using 语句,所以这里将它们作为要点:
  • 使用系统;
  • 使用 System.Collections.Generic;
  • 使用 System.ComponentModel.Composition;
  • 使用 System.ComponentModel.Composition.Hosting;
  • 使用 System.Drawing;
  • 使用 System.IO;
  • 使用 System.Windows.Forms;
  • 使用合约接口(interface);
  • (命名空间)主程序

  • public partial class Form1 : Form
    {
    // Prerequisites to run:
    // 1) Project, Add Reference, Projects, ContractInterface
    // 2) Project, Add Reference, .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 控件,并将其保留在窗体的右侧。从插件动态创建的文本框将显示在左侧。

    接下来添加一个名为“ContractInterfaces”的类项目,然后包含以下代码:
  • 使用 System.Windows.Forms;
  • (命名空间)契约(Contract)接口(interface)

  • // Prerequisites to run:
    // 1) Project, Add Reference, .NET, "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;
  • 使用合约接口(interface);
  • (命名空间) PlugInA

  •     // Prerequisites to run:
    // 1) Project, Add Reference, Projects, "ContractInterface"
    // 2) Project, Add Reference, .NET, "System.Windows.Forms"
    // 3) Project, Add Reference, .NET, "System.ComponentModel.Composition"
    // 4) Project, Properties, Build Events, Post-Build event command line:
    // xcopy "$(ProjectDir)$(OutDir)$(TargetFileName)" "$(SolutionDir)Plug-Ins\" /Y
    // 5) Project, Properties, Build Events, Run the post-build event:, Always
    // 6) Project, Properties, 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;
  • 使用合约接口(interface);
  • (命名空间) PlugInB

  • // Prerequisites to run:
    // 1) Project, Add Reference, Projects, "ContractInterface"
    // 2) Project, Add Reference, .NET, "System.Windows.Forms"
    // 3) Project, Add Reference, .NET, "System.ComponentModel.Composition"
    // 4) Project, Properties, Build Events, Post-Build event command line:
    // xcopy "$(ProjectDir)$(OutDir)$(TargetFileName)" "$(SolutionDir)Plug-Ins\" /Y
    // 5) Project, Properties, Build Events, Run the post-build event:, Always
    // 6) Project, Properties, 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 = "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;
  • 使用合约接口(interface);
  • (命名空间) PlugInC

  • // Prerequisites to run:
    // 1) Project, Add Reference, Projects, "ContractInterface"
    // 2) Project, Add Reference, .NET, "System.Windows.Forms"
    // 3) Project, Add Reference, .NET, "System.ComponentModel.Composition"
    // 4) Project, Properties, Build Events, Post-Build event command line:
    // xcopy "$(ProjectDir)$(OutDir)$(TargetFileName)" "$(SolutionDir)Plug-Ins\" /Y
    // 5) Project, Properties, Build Events, Run the post-build event:, Always
    // 6) Project, Properties, 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 = "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

    右键单击解决方案,然后选择“项目依赖项...”。设置依赖项如下:
  • MainProgram - 取决于 - ContractInterface
  • PlugInA - 取决于 - ContractInterface
  • PlugInB - 取决于 - ContractInterface
  • PlugInC - 取决于 - ContractInterface
  • ContractInterface - 取决于 - [nothing]

  • 右键单击解决方案,然后选择“项目构建顺序...”。构建顺序应如下所示:
  • 契约(Contract)界面
  • 插件
  • 插件B
  • PlugInC
  • 主程序

  • 构建并运行程序。您应该会看到 3 个 DLL 文件复制到与解决方案文件 (*.sln) 相同目录级别的新“插件”文件夹中。如果没有,请检查项目构建顺序、依赖关系,以及您是否根据上面插件代码中的注释输入了构建后事件。如果文件在那里,那么 ListView 应该用插件条目填充到表单中。双击每个 ListView 条目以启动插件。

    玩得开心,我希望这对某人有帮助....

    关于c# - 如何使用 MEF 在插件 DLL 的元数据中包含图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14634082/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com