Здравствуйте, Аноним, Вы писали:
А>Нужно сделать следующее: есть приложение, где форма оформленна для MDI. Есть директория, кде находятся сборки. Приложения должно просматривать всю директорию и загружать находящиеся там сборки. Сборки должны добавлять на главную форму свои пункты меню, и кнопки на панель инструментов.И дальше уже при выборе нужных пунктов меню, должны вызывать функции и показываться формы находящиеся в сборках.
А>Как это реализовать?
А>Скажите, в какую сторону копать?
Подключаем сборки через Reflection
1. Загружаем сборку
/// <summary>
/// Кеш загруженных сборок
/// </summary>
/// <param name="AssemblyFileName"></param>
/// <returns></returns>
private static Assembly GetAssembly(string AssemblyFileName)
{
if(AssemblyDictionary==null) AssemblyDictionary=new ListDictionary();
if(AssemblyDictionary.Contains(AssemblyFileName))
return AssemblyDictionary[AssemblyFileName] as Assembly;
else
{
//проверка наличия файла
if (!File.Exists(AppDomain.CurrentDomain.BaseDirectory + @"Plugins\" + AssemblyFileName))
{
Debuger.LogDebug( "Не удалось найти плагин " + AppDomain.CurrentDomain.BaseDirectory + @"Plugins\" + AssemblyFileName,null,AM.Messaging.MessageType.Error);
return null;
}
//загружаем сборку плагина в этот домен
Assembly ass = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + @"Plugins\" + AssemblyFileName);
if(ass!=null)
AssemblyDictionary.Add(AssemblyFileName,ass);
return ass;
}
}
2. Создаем экземпляр заданного класса в сборке
/// <summary>
/// Загружает из заданной сборки заданный тип
/// </summary>
/// <param name="RequiredType">Имя файла сборки без указания пути</param>
/// <param name="ConstructorArguments">Имя файла сборки без указания пути</param>
/// <param name="AssemblyFileName">Имя файла сборки без указания пути</param>
public static object LoadInstanceOf(Type RequiredType, object[] ConstructorArguments, string AssemblyFileName)
{
Assembly ass = GetAssembly(AssemblyFileName); if(ass==null) return null;
try
{
//ищем входной объект плагина
foreach (Type type in ass.GetTypes())
{
if(type.BaseType == RequiredType)
{
//Создаем экземпляр класса
return Activator.CreateInstance(type,ConstructorArguments);
}
}
return null;
}
catch (Exception ex) //перехватываем исключения в плагинах
{
.......
}
return null;
}
#endregion
Теперь по общим вопросам.
1. Я разделяю в плагине сборки конфигурацию (PluginConfiguration) и формы (PluginForm). Когда главная форма загружает необходимый плагин она загружает конфигурацию которая предоставляет информацию основной форме к примеру
PluginConfigurationInstance.GetMenuItems(MenuItemCategory.File);
PluginConfigurationInstance.GetToolBars();
и соответственно главная MDI форма выстраивает свои меню и тулбары в соответствии с данными полученными из PluginConfiguration.
2. Каждому пункту меню и кнопке тулбара в плагине соответствует некая PluginCommand (см паттерн Command). Она управляет доступностью элементов меню и кнопок в определенный момент а так же выполняет действие внутри плагина при нажатии пункта меню(кнопки тулбара)
В итоге как мне кажеться получается достаточно слабое связывание.
При добавлении дочерних форм PluginForm, PluginConfiguration посылает событие основной форме и та уже устанавливает себя в качестве родительской PluginForm
Это если вкратце
А>Зарание большое спасибо!