Доступ к элементам управления окнами из внешних библиотек в C # - PullRequest
0 голосов
/ 06 сентября 2018

Это моя первая тема здесь, и я не нашел подобных тем, поэтому стараюсь описать свою проблему настолько хорошо, насколько могу:

Моя компания приказала мне создать модульную программу на C #, чтобы помочь нашим разработчикам программного обеспечения справиться с заданиями. Программа состоит из приложения Windows Forms с пользовательским интерфейсом, который вызывает внешние библиотеки DLL, которые выполняют реальную работу. Все эти DLL написаны мной и следуют определенным правилам, чтобы сделать их совместимыми с Основным приложением. Таким образом, я легко могу добавить новые функции в Программу, просто поместив DLL в предопределенную папку. Так сказать Plug-and-Run

Основная программа содержит ListBox, который показывает все доступные подключаемые модули, и если выбрано одно из них и нажата кнопка «Пуск», основная программа вызывает соответствующую DLL и вызывает метод «программа», запускающий фактическую функцию DLL. Кроме того, Main содержит метод «Output», который должен записывать результат каждого плагина на вкладку моего TabControl. Таким образом, результаты каждого плагина, работающего в отдельных потоках, можно просматривать независимо. Доступ к вкладке уже имеет делегата, чтобы сделать его потокобезопасным. Информация собирается путем вызова из собственного метода плагина "returnOutput", который просто возвращает список строк, содержащих результаты, в Main.

Моя проблема сейчас такова: как я могу внедрить тип обратного вызова в мои подключаемые библиотеки DLL, чтобы они могли приказать основной программе собрать результаты в любое время?

Моя первая идея состояла в том, чтобы просто добавить результат в качестве возвращаемых значений к самому методу «программы», но это сделало бы информацию доступной только в конце программы, а некоторые задачи требуют «живого обновления» во время выполнения.

Моя вторая идея состояла в том, чтобы использовать делегат для элемента управления в качестве параметра и передавать его в подключаемый модуль, чтобы DLL-библиотека подключаемого модуля могла получить доступ к элементу управления самостоятельно. Эта идея не удалась, потому что DLL не «знает» программу Main и не может получить доступ к ее методам или экземпляру делегатов, поэтому я всегда пропускаю ссылку.

Есть ли способ решить мою проблему? При необходимости я могу предоставить фрагменты кода, но в программе уже около 800 строк кода, и каждый плагин добавляет еще несколько сотен ..

Заранее спасибо за каждый ответ и извините за мой не родной английский: D

С наилучшими пожеланиями

Геррит "Raketenmaulwurf" M.

Редактировать: я использую SharpDevelop 5.1

Фрагмент кода для вызова DLL:

PlugIn = PlugIns.SelectedItem.ToString();
Assembly PlugInDLL = Assembly.LoadFile(@PlugInOrdner+"\\"+PlugIn+".dll");
Object Objekt = PlugInDLL.CreateInstance("DLL.PlugIn");
MethodInfo Info1 = Objekt.GetType().GetMethod("Programm");
Info1.Invoke(Objekt, new Object[]{Projekt, TIAInstanz});

он в основном ищет файл DLL, имя которого совпадает с именем выделенного элемента в ListBox

1 Ответ

0 голосов
/ 06 сентября 2018

Есть много разных способов сделать это. Некоторые из предложений в комментариях действительно хороши, и их реализация создаст надежное и расширяемое решение.

Если вы ищете быстрый и простой способ получения сообщений из ваших плагинов, вы можете передать свой обратный вызов непосредственно плагину в качестве действия:

public class PluginRunner
{
    public class PluginMessageEventArgs
    {
        public string Text { get; set; }
    }

    public event EventHandler<PluginMessageEventArgs> PluginMessage;

    public void Run( string pluginPath )
    {
        Assembly PlugInDLL = Assembly.LoadFile(pluginPath);
        Object Objekt = PlugInDLL.CreateInstance("DLL.PlugIn");
        MethodInfo Info1 = Objekt.GetType().GetMethod("Programm");
        Info1.Invoke(Objekt, new Object[] { Projekt, TIAInstanz, new Action<string>(Log) });
    }

    private void Log(string s)
    {
        PluginMessage?.Invoke(this, new PluginMessageEventArgs { Text = s });
    }

}

так что вы можете использовать его как:

    var path =
            Path.Combine(
                Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
                "Plugins",
                "MyAwesomePlugin.dll");

    var pr = new PluginRunner();
    // be aware that your event delegate might be invoked on a plugin's thread, not the application's UI thread!
    pr.PluginMessage += (s,e) => Console.WriteLine("LOG: " + e.Text);
    pr.Run(path);

тогда метод Program вашего плагина записывает свои логи:

    public void Programm( ProjektClass p0, TIAClass p1, Action<string> log )
    {
        Task.Run(() =>
        {
            // do something
            log.Invoke("here am I!");
            // do something else
            log.Invoke("here am I again!");
            // do something more
        });
    }

Я должен признать, что это не идеальный способ борьбы с сообщениями. Существуют гораздо лучшие (и, к сожалению, более сложные для реализации) решения. Этот довольно простой, хотя. Только не забывайте, что вы получаете сообщение в той же ветке, в которой его отправили, и избегайте взаимоблокировок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...