Эта форма Windows должна также содержать тип Listbox (которому здесь назначено имя lstLoadedSnapIns), используемый для отображения имен подключаемых модулей, загружаемых пользователем. На рис. 12.12 показан окончательный вид графического интерфейса приложения, о котором идет речь.
Рис. 12.12. Окончательный вид графического интерфейса MyExtendableApp
Программный код для обработки выбора Сервис→Подключаемый модуль из меню (этот программный код можно создать с помощью двойного щелчка на пункте меню в окне проектирования формы), отображает диалоговое окно Открытие файла и читает путь к выбранному файлу. Соответствующая строка пути затем посылается вспомогательной функции LoadExternalModule() для обработки. Метод возвращает false (ложь), если он не обнаруживает класс, реализующий IAppFunctionality.
private void snapInModuleToolStripMenuItem_Click(object sender, EventArgs e) {
// Позволяет пользователю выбрать компоновочный блок для загрузки.
OpenFileDialog dlg = new OpenFileDialog();
if (dlg.ShowDialog() == DialogResult.OK) {
if (LoadExternalModule(dlg.FileName) == false) MessageBox.Show("Нет реализации IAppFunctionality!");
}
}
Метод LoadExternalModule() решает следующие задачи.
• Динамически загружает компоновочный блок в память.
• Выясняет, содержит ли компоновочный блок тип, реализующий IAppFunctionality
Если тип, реализующий IAppFunctionality, обнаружен, вызывается метод DoIt(), и абсолютное имя типа добавляется в Listbox (заметьте, что цикл for должен выполнить проход по всем типам компоновочного блока, чтобы учесть возможность наличия в одном компоновочном блоке нескольких модулей расширения).
private bool LoadExternalModule(string path) {
bool foundSnapIn = false;
IAppFunctionality itfAppFx;
// Динамическая загрузка выбранного компоновочного блока.
Assembly theSnapInAsm = Assembly.LоadFrom(path);
// Получение всех типов компоновочного блока.
Tуре[] theTypes = theSnapInAsm.GetTypes();
// Поиск типа с реализацией IAppFunctionality.
for (int i = 0; i ‹ theTypes.Length; i++) {
Type t = theTypes[i].GetInterface("IAppFunctionality");
if (t != null) {
foundSnapIn = true;
// Динамическое связывание для создания типа.
object о = theSnapInAsm.CreateInstance(theTypes[i].FullName);
// Вызов DoIt() через интерфейс.
itfAppFx = о as IAppFunctionality;
itfAppFx.DoIt();
lstLoadedSnapIns.Items.Add(theTypes[i].FullName);
}
}
return foundSnapIn;
}
Теперь вы можете выполнить свое приложение. При выборе компоновочных блоков CSharpSnapIn.dll и VbNetSnapIn.dll вы должны увидеть соответствующее сообщение. На рис. 12.13 показан один из возможных вариантов выполнения.
Рис. 12.13. Подключение внешних компоновочных блоков
Завершающей задачей будет отображение метаданных, соответствующих атрибуту [CompanyInfo]. Для этого просто обновите LoadExternalModule(), чтобы перед выходом из контекста if вызывалась новая вспомогательная функция DisplayCompanyData(). Эта функция имеет один параметр типа System.Type.
private bool LoadExternalModule(string path) {
…
if (t != null) {
…
// Отображение информации о компании.
DisplayCompanyData(theTypes[i]);
}
return foundSnapIn;
}
Для поступающего на вход типа просто отобразите атрибут [CompanyInfo].
private void DisplayCompanyData(Type t) {
// Получение данных [CompanyInfo].
object[] customAtts = t.GetCustomAttributes(false);
// Вывод данных.
foreach (CompanyInfoAttribute с in customAtts) {
MessageBox.Show(с.Url, String.Format("Дополнительные сведения о {0} ищите по адресу", с.Name));
}
}