Как вызвать, если форма не активна? - PullRequest
1 голос
/ 25 апреля 2009

До этого момента я использовал этот метод для вызова:

    public string AddText
    {
        set
        {
            if (listView1.InvokeRequired)
            {
                this.Invoke((MethodInvoker)delegate
                {
                    Textbox.text += value + "\n";
                });
            }
            else
            {
                Textbox.text += value + "\n";
            }
        }
    }

А вот и проблема:

    var form = Form.ActiveForm as Form1;
    if (form != null)
        form.AddText = "Test";

Я пишу анализатор, который анализирует пакеты. Я не могу постоянно фокусировать форму, потому что я должен выполнять действия над приложением. Я пишу этот анализатор, чтобы получить пакет, чтобы я мог его проанализировать.

Если я касаюсь приложения, я хочу проанализировать Form.ActiveForm возвращает ноль.

Есть ли способ, которым я могу вызывать и устанавливать текстовое поле для добавления текста, даже если форма находится не поверх всего?

Ответы [ 4 ]

2 голосов
/ 26 апреля 2009

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

Вы можете перевернуть проблему и вызвать событие из класса, который анализирует пакеты. Это дает вам намного лучшую инкапсуляцию, потому что теперь анализатору пакетов ничего не нужно знать об остальной части приложения. Вы можете создать свои собственные аргументы событий или использовать их, например, System.Diagnostics.DataReceivedEventArgs. Затем ваша форма может поглотить событие DataReceived и вызвать свой собственный AddText для вызова обратно в основной поток, и она будет работать независимо от того, является ли форма видимой или нет.

По крайней мере, это будет работать, но это блокирующий вызов, поэтому поток анализатора пакетов будет остановлен до тех пор, пока форма полностью не обработает событие и не вернется маршализованный вызов к основному потоку. Это было бы хорошо, если скорость передачи пакетов не очень высока, но обычно вы не хотите останавливать коммуникационный поток, чтобы дождаться, пока основной поток обновит текстовое поле. Другой подход заключается в регистрации текста с использованием StringBuilder внутри анализатора пакетов и предоставлении его (накопленный текст, а не StringBuilder) через открытое для потока общедоступное свойство. Или, если вам нужно разделить отдельные сообщения, вы можете добавить их, например, в список, и иметь свойство, безопасное для потоков, возвращать массив накопленных сообщений. Тогда ваша форма может опрашивать анализатор на наличие новых зарегистрированных данных с использованием таймера с любой частотой, подходящей для вашего приложения, и только тогда, когда форма видна. Обновление не будет таким быстрым, но влияние на поток анализатора будет почти нулевым, и в целом он должен работать быстрее, если он объединяет много сообщений внутри StringBuilder или List между обновлениями, а не объединяет свойство Text с каждым отдельным пакетом.

1 голос
/ 26 апреля 2009

Разделите проблему на две части. Зарегистрируйте свой текст, используя Trace.TraceInformation(), и реализуйте TraceListener, который обрабатывает аспект отображения.

Таким образом, вы можете перенаправить вывод журнала в файл, или в EventLog Windows, или в свой пользовательский интерфейс, или что-то еще, просто с помощью записи в файле конфигурации. Вам не нужно выбирать только один. Вы можете сделать все вышеперечисленное, если это поможет.

Это такая обычная и частая проблема, что образец MSDN для реализации TraceListener - это именно то, что вам нужно.

1 голос
/ 26 апреля 2009

Если проблема, которую вы не можете вызвать, тогда ваш ответ будет использовать SynchronizationContext , он всегда доступен в потоке Application.Run. Так что сделайте следующее:

В форме OnLoad сохраните SynchronizationContext.Current в любом месте статического поля. После этого вы можете легко использовать методы Post или Send для синхронизации или асинхронных вызовов в потоке GUI.

Описание здесь: http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.aspx

Хорошая статья здесь: http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx

1 голос
/ 25 апреля 2009

Вы можете использовать шаблон единицы работы для этого с событием OnActivation формы.

Поставьте флажок «если активна форма» в вашем методе AddText. если форма не активна, поместите текст в список на потом.

Затем обработайте событие OnActivation формы, и, если в списке есть значения, верните их обратно в AddText. Затем, когда форма активируется (это происходит, когда форма получает фокус), текст заполнится.

Даже если часть OnActivation не работает, эта общая скороговорка должна сработать.

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