Ошибка компиляции C#: "Invoke или BeginInvoke не могут быть вызваны для элемента управления, пока не будет создан дескриптор окна."

Я только что опубликовал вопрос о том, как заставить делегата обновить текстовое поле в другой форме. Как раз когда я думал, что у меня есть ответ с помощью Invoke...такое случается. Вот мой код:

Основной Код Формы:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Data.OleDb;
using System.Collections.Specialized;
using System.Text;
using System.Threading;

delegate void logAdd(string message);

namespace LCR_ShepherdStaffupdater_1._0
{
    public partial class Main : Form
    {
        public Main()
        {
            InitializeComponent();
        }

        public void add(string message)
        {
            this.Log.Items.Add(message);
        }
        public void logAdd(string message)
        {   /////////////////////////// COMPILER ERROR BELOW ///////////
            this.Invoke(new logAdd(add), new object[] { message }); // Compile error occurs here     
        }////////////////////////////// COMPILER ERROR ABOVE ///////////

        private void exitProgramToolStripMenuItem_Click(object sender, EventArgs e) 
        {
            Application.Exit(); 
        }
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Form aboutBox = new AboutBox1(); 
            aboutBox.ShowDialog(); 
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            settingsForm.settings.ShowDialog();
        }

        private void synchronize_Click(object sender, EventArgs e)
        {
            string message = "Here my message is"; // changed this
            ErrorLogging.updateLog(message);  // changed this
        }

    }

    public class settingsForm 
    {
        public static Form settings = new Settings();
    }

}

Код Класса Регистрации:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LCR_ShepherdStaffupdater_1._0
{
    public class Logging
    {
        static Main mainClass = new Main();
        static logAdd logAddDelegate;

        public static void updateLog(string message)
        {
            logAddDelegate = mainClass.logAdd;
            logAddDelegate(message);
        }
    }
}
  • Ошибка Компиляции:

    исключение InvalidOperationException было необработанный-Invoke или BeginInvoke невозможно вызвать элемент управления до дескриптор окна создан.

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

пожалуйста, скажите мне, как создать дескриптор, прежде чем я вызову этот делегат. Пока вы на нем, дайте мне несколько способов сделать этот код более простым. Например, я не хочу две функции Add... Мне пришлось это сделать, потому что я не мог найти элемент для вызова из класса Logging. Есть ли лучший способ выполнить то, что мне нужно сделать?

спасибо!!!

EDIT:

мой проект довольно большой, но это единственные элементы, вызывающие эту конкретную проблему.

Log это мой RichTextBox1 (Log.Предметы.Add (message)) я переименовал его в Log, поэтому его легче перепечатать.

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

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

второй EDIT:

Я думаю, я нашел проблему, но не знаю как это исправить.

в моем классе ведения журнала я использую этот код для создания mainClass:

static Main mainClass = новый Main ();

Я создаю совершенно новую реплику blueprint для Main (), включая Log (richtextbox, который я пытаюсь обновить)

когда я вызываю updateLog (сообщение), Я считаю, что пытаюсь обновить журнал (richtextbox) на второй объект Main (), иначе известный как mainClass. Конечно, это бросит мне это исключение, потому что я даже не видел эту реплику текущего Main, который я использую.

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

Main mainClass = Application.OpenForms.OfType<Main>().First();
logAddDelegate = mainClass.logAdd; 
logAddDelegate(message);

мне нужно создать mainClass не с оператором new (), потому что я не хочу создавать новую схему формы, которую я хочу иметь возможность редактировать текущую форму.

приведенный выше код не хотя, я даже не могу найти применение. Это даже синтаксис C#?

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

ОКОНЧАТЕЛЬНОЕ РЕДАКТИРОВАНИЕ:

я понял это благодаря одному из пользователей ниже. Вот мой обновленный код:

Основной Код Формы:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Data.OleDb;
using System.Collections.Specialized;
using System.Text;
using System.Threading;

delegate void logAdd(string message);

namespace LCR_ShepherdStaffupdater_1._0
{
    public partial class Main : Form
    {
        private static Main mainFormForLogging;
        public static Main MainFormForLogging
        {
            get
            {
                return mainFormForLogging;
            }
        }

        public Main()
        {
            InitializeComponent();
            if (mainFormForLogging == null)
            {
                mainFormForLogging = this;
            }
        }

        public void add(string message)
        {
            this.Log.Items.Add(message);
        }
        public void logAdd(string message)
        {
            this.Log.BeginInvoke(new logAdd(add), new object[] { message });
        }

        private void exitProgramToolStripMenuItem_Click(object sender, EventArgs e) 
        {
            Application.Exit(); 
        }
        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Form aboutBox = new AboutBox1(); 
            aboutBox.ShowDialog(); 
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            settingsForm.settings.ShowDialog();
        }

        private void synchronize_Click(object sender, EventArgs e)
        {
            add("test");
            Logging.updateLog("testthisone");
            //DatabaseHandling.createDataSet();
        }

    }

    public class settingsForm 
    {
        public static Form settings = new Settings();
    }

}

Класс Ведения Журнала Код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LCR_ShepherdStaffupdater_1._0
{
    public class Logging
    {

        static Main mainClass = Main.MainFormForLogging;
        static logAdd logAddDelegate;

        public static void updateLog(string message)
        {
            logAddDelegate = mainClass.logAdd;
            logAddDelegate(message);
        }
    }
}

9 ответов


Я решил это в прошлом, используя следующий метод:

private void invokeOnFormThread(MethodInvoker method)
{
    if (IsHandleCreated)
         Invoke(new EventHandler(delegate { method(); }));
    else
        method();
}

вызов invokeOnFormThread вместо вызова. Он будет использовать поток формы только в том случае, если дескриптор уже создан, иначе он будет использовать поток вызывающего.


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

в WinForms элементы GUI имеют две полунезависимые жизни: как классы в памяти и как сущности в операционной системе. Таким образом, можно ссылаться на элемент управления в .net, который еще не был создан. "Создаваемый дескриптор" означает номер, присвоенный элементу управления ОС, чтобы программы могли управлять его свойства.

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


Это ошибка времени выполнения, а не ошибка компилятора.

ваша форма, "Main", должна быть отображена (следовательно, создан дескриптор окна), прежде чем вы сможете сделать вызовы BeginInvoke или вызвать на нем.

что я обычно делаю в этих ситуациях, это оставляю его до формы, чтобы определить, нужно ли использовать вызов BeginInvoke или Invoke. Вы можете проверить это с помощью вызова InvokeRequired (проверьте MSDN).

поэтому для начала я бы избавился от вызова logAddDelegate в Loggin метод updateLog класса. Просто позвоните прямо в форму, чтобы добавить журнал. Вот так:

public partial class Main : Form
{
    public Main()
    {
        InitializeComponent();
    }

    private delegate void AddNewLogMessageEventHandler(string message);

    public void AddLogMessage(string message)
    {
        object[] args = new object[1];
        args[0] = message;

        if (InvokeRequired)
            BeginInvoke(new AddNewLogMessageEventHandler(AddLog), args);
        else
            Invoke(new AddNewLogMessageEventHandler(AddLog), args);
    }

    private void AddLog(string message)
    {
        this.Log.Items.Add(message);
    }
 }

}

таким образом, Вы можете видеть, что сама форма отвечает за определение, нужно ли ей вызывать метод асинхронно или нет.

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


эта ошибка имеет тенденцию происходить, если вы вызываете в окне, которое еще не было "показано". Вы уверены, что не создаете второй экземпляр основного класса с вашим кодом в классе ведения журнала (в частности, в первой строке)? Возможно, основная форма, которую вы вызываете, не является основной формой, на которую вы смотрите. Если вы хотите проверить, добавьте вызов в " MainClass.Show () " только внутри вашего регистрационного вызова. Если вы получите вторую копию основной формы, то проблема в том, что ваша класс logging не ссылается на правильный "экземпляр" вашей формы.

подумайте о классе как о "проекте". Каждый экземпляр класса (созданный со словом "новый") - это еще один объект, созданный из чертежа. То, что два объекта (в данном случае две основные формы) имеют одинаковую схему, не означает, что вы можете использовать их взаимозаменяемо. В этом случае, у вас уже есть главная форма, и вы хотите повторно использовать его. Вы можете попробовать:

MainClass myMainForm = Application.OpenForms.OfType<MainClass>().First();
logAddDelegate = myMainForm.logAdd; 
logAddDelegate(message);

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

надеюсь, что это помогает.


Это поможет в случае, если какой-либо другой человек был пойман с этим. Моя проблема: VB.net: "Invoke или BeginInvoke нельзя вызвать для элемента управления, пока не будет создан дескриптор окна." Я закрыл форму, которая имеет обработчик для события, вызываемого для обновления делегата, без удаления обработчика для события.

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


logAddDelegate(сообщение);

Я думаю, вы вызываете это до того, как событие Form_Load было вызвано. Исправьте код, чтобы дождаться загрузки формы перед вызовом logAddDelegate (...) т. е. перед вызовом журнала.updateLog()


это ваш точный код? Ты зовешь this.Log.Items.Add(message); в вашем методе add (string), но ваш класс ведения журнала называется Logging, а не Log. У вас другая форма называется журнал возможно? Если эта форма не была создана при вызове метода add, вы получите это исключение.


нашел InvokeRequired не надежный, поэтому я просто использую

if (!this.IsHandleCreated)
{
    this.CreateHandle();
}