Tìm thấy một giải pháp:
OK, như xa như tôi có thể nói, bạn có thể không sử dụng hình ảnh hoặc biểu tượng trong siêu dữ liệu MEF. Tuy nhiên, bạn có thể gán một biểu tượng cho tệp DLL, giống như bạn có thể cho các tệp EXE. Các biểu tượng sau đó có thể được đọc bằng cách sử dụng phương pháp tĩnh được xây dựng vào loại Biểu tượng cho NET:
Icon MyDLLIcon = Icon.ExtractAssociatedIcon(DLLFilePath);
Tôi vẫn không chắc chắn chính xác lý do tại sao bạn có thể trở lại chuỗi từ một tập tin tài nguyên như siêu dữ liệu MEF, nhưng không được nhúng Icons hoặc Hình ảnh.
Vì tôi đã cố gắng ghép nối với nhau một chương trình ví dụ hoạt động cung cấp trình đơn Trình cắm có biểu tượng trong một vài ngày, tôi đã đoán rằng tôi sẽ đăng mã trong trường hợp nó giúp bất kỳ ai khác.
Đây là một ví dụ dự án đầy đủ chức năng với các tính năng sau:
Mục đích để có một giải pháp duy nhất với 5 dự án (MainProgram, ContractInterfaces, PlugInA, PlugInB, PlugInC)
Sự kiện xây dựng bài đăng sẽ tự động sao chép các tệp DLL từ mỗi dự án vào một thư mục "Plugin" phổ biến
Ma dự án inProgram (WinForm) sẽ xây dựng một danh mục các Plugin DLL có sẵn và điền vào một ListView với các Biểu tượng và siêu dữ liệu Tiêu đề của mỗi Trình cắm thêm
Nhấp đúp vào mục ListView sẽ khởi tạo Trình cắm (tận dụng Lazy instantiation), và bắt đầu nó.
Mỗi trình cắm sẽ nhận được tham chiếu đến Biểu mẫu chính khi khởi động, tạo một TextBox mới và đăng lên Biểu mẫu chính để chứng minh rằng nó chạy và có thể truy cập GUI.
Các Tiêu đề, mô tả, và phiên bản giá trị siêu dữ liệu của chọn Plug-In sẽ in ra cửa sổ Console
tôi gán một biểu tượng khác nhau cho mỗi DLL (từ Visual Studio cũ 6 Common Graphics misc thư mục)

các biểu tượng được trích xuất từ các DLL plug-Ins để tạo ra các ListView, và thứ Các TextBox được tạo ra và được đăng bởi các DLL vào GUI khi chúng bắt đầu (sau khi kích đúp vào mỗi mục Plug-In trong ListView).
Thêm mã sau đây để một mới C# WinForm dự án mới mang tên "MainProgram" (tôi sử dụng VS 2010):
Đối với một số lý do các mẫu phân tích cú pháp Mã không thích những điều khoản Sử dụng, vì vậy ở đây họ là điểm bullet:
- using System;
- bằng System.Collections.Generic;
- bằng System.ComponentModel.Composition;
- bằng System.ComponentModel.Composition.Hosting;
- using System.Drawing;
- bằng System.IO;
- bằng System.Windows.Các hình thức;
- sử dụng ContractInterfaces;
- (namespace) MainProgram
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; }
}
Bây giờ thêm một điều khiển ListView được gọi là "listView1" vào Form chính, và giữ cho nó sang phía bên phải của Mẫu. Các TextBox được tạo động từ Plug-Ins sẽ hiển thị bên trái.
Tiếp theo, thêm một dự án lớp gọi là "ContractInterfaces", sau đó bao gồm mã này:
- sử dụng System.Windows.Forms;
- (namespace) ContractInterfaces
// 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; }
}
Tiếp theo, thêm một dự án lớp gọi là "PlugInA", sau đó bao gồm mã này:
- using System;
- bằng System.ComponentModel.Composition;
- bằng System.Windows.Forms;
- sử dụng ContractInterfaces;
- (namespace) 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";
}
}
Tiếp theo, thêm một dự án lớp gọi là "PlugInB", sau đó bao gồm mã này:
- using System;
- bằng System.ComponentModel.Composition;
- bằng System.Windows.Forms;
- sử dụng ContractInterfaces;
- (namespace) 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";
}
}
Tiếp theo, thêm một dự án lớp gọi là "PlugInC", sau đó bao gồm mã này:
- using System;
- bằng System.ComponentModel.Composition;
- bằng System.Windows.Các hình thức;
- sử dụng ContractInterfaces;
- (namespace) 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";
}
}
Giải pháp nên xem xét như thế này:

Nhấp chuột phải vào các giải pháp, và chọn "Proje ct Phụ thuộc ... ". Đặt phụ thuộc như sau:
- MainProgram - phụ thuộc vào - ContractInterface
- PlugInA - phụ thuộc vào - ContractInterface
- PlugInB - phụ thuộc vào - ContractInterface
- PlugInC - phụ thuộc vào - ContractInterface
- ContractInterface - phụ thuộc vào - [không có gì]
Nhấp chuột phải vào Giải pháp và chọn "Project Build O rder ... ". Việc xây dựng trật tự nên thực hiện như sau:
- ContractInterface
- PlugInA
- PlugInB
- PlugInC
- MainProgram
xây dựng và chạy chương trình. Bạn sẽ thấy 3 tệp DLL được sao chép vào một thư mục "Plug-Ins" mới ở cùng cấp thư mục với tệp Solution (* .sln). Nếu không, hãy kiểm tra Thứ tự xây dựng dự án, Phụ thuộc và bạn đã nhập Sự kiện sau khi xây dựng theo ghi chú trong mã Trình cắm ở trên. Nếu các tệp ở đó, thì ListView sẽ được điền trong Biểu mẫu có các mục trình cắm thêm. Bấm đúp vào mỗi mục nhập ListView để khởi động Trình cắm.
Hãy vui vẻ, tôi hy vọng điều này sẽ giúp ai đó ...
Giới hạn bạn gặp phải là vấn đề thuộc tính chứ không phải của MEF. Họ khá hạn chế trong những gì họ có thể nắm giữ. Bạn sẽ ví dụ: đã có thể lưu trữ đường dẫn đến tài nguyên thre dưới dạng chuỗi và sau đó có thuộc tính Hình ảnh mà bạn không đặt nhưng sau đó sử dụng đường dẫn để đọc tài nguyên được nhúng. – flq
Tôi muốn truyền biểu tượng qua Siêu dữ liệu để tôi không phải khởi tạo Hội đồng trình cắm thêm chỉ để tạo một menu. Giải pháp ở trên hoạt động xung quanh vấn đề đó, nhưng tôi tin rằng bạn là chính xác - đó là một vấn đề với những hạn chế đối với các loại đối tượng có thể được nhúng trong các thuộc tính. – user1689175
Nếu tôi bao gồm loại Biểu tượng trong siêu dữ liệu, mọi thứ biên dịch sẽ chạy đến câu lệnh ** container.ComposeParts (this); **, trả về lỗi: _Property 'PlugInA.PluginMetadataAttribute.PlugInIcon' có loại 'System.Drawing .Icon 'là loại siêu dữ liệu không hợp lệ. Siêu dữ liệu chỉ có thể chứa các giá trị có loại có sẵn để được nhúng vào lúc biên dịch thành các thuộc tính. Để biết thêm chi tiết về những loại nào là tham chiếu hợp lệ trong phần 17.1.3 trong đặc tả C#._ – user1689175