C# 컴파일 오류 : "창 핸들이 생성 될 때까지 컨트롤에서 호출 또는 시작을 호출 할 수 없습니다."

StackOverflow https://stackoverflow.com/questions/513131

문제

방금 대의원이 다른 양식의 텍스트 상자를 업데이트하는 방법에 대한 질문을 게시했습니다. 내가 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은 처리되지 않았습니다 - 창고 핸들이 생성 될 때까지 호출 또는 시작 인 블로크를 컨트롤에서 호출 할 수 없습니다.

이미 로그 항목에 핸들을 만들려고했지만 작동하지 않았습니다. 문제는 내가하고있는 일에 대한 단서가없고 Google을 검색했습니다. 널리 모호한 답변을 찾기 위해서만.

이 대의원을 호출하기 전에 핸들을 만드는 방법을 알려주세요. 당신이 그것에있는 동안, 나는이 코드를 더 간단하게 만들 수있는 몇 가지 방법을 알려주십시오. 예를 들어, 나는 두 개의 추가 함수를 원하지 않습니다 ... 로깅 클래스에서 호출 할 항목을 찾을 방법이 없었기 때문에 그렇게해야했습니다. 내가해야 할 일을 성취하는 더 좋은 방법이 있습니까?

고맙습니다!!!

편집하다:

내 프로젝트는 상당히 크지만이 특정 문제를 일으키는 유일한 항목입니다.

통나무 내 richtextbox1 (log.items.add (message))입니다. 나는 그것을 로그로 이름을 변경하여 더 쉽게 다시 입력 할 수 있습니다.

그래도 다른 형식에서 updateLog (메시지)를 호출하고 있습니다 ... 여기에서 업데이트하겠습니다.

너희들은 나에게 더 간단한 일을 만들고 예를 제공해야 할 것이다. 나는 여러분이 여기서 말하는 모든 것의 절반을 이해하지 못합니다 ... 나는 방법과 핸들을 호출하는 방법에 대한 단서가 없습니다. 나도 쓰레기를 조사했다 ...

두 번째 편집 :

나는 문제를 찾았다 고 생각하지만 문제를 해결하는 방법을 모른다.

로깅 클래스 에서이 코드를 사용하여 메인 클래스를 만듭니다.

정적 메인 메인 클래스 = 새로운 main ();

나는 main ()에 완전히 새로운 청사진 복제본을 만들고있다. 통나무 (업데이트하려는 RichTextBox)

UpdateLog (메시지) 호출 할 때 메인 클래스라고 알려진 Main ()의 두 번째 엔티티에서 로그 (RichTextBox)를 업데이트하려고한다고 생각합니다. 물론, 그렇게하는 것은 내가 사용중인 현재 메인의 복제본조차 보지 못했기 때문에이 예외를 던질 것입니다.

이것이 제가 촬영하는 것입니다. 답을 주신 사람들 중 한 명 덕분입니다.

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

현재 양식을 편집 할 수있는 양식의 새로운 청사진을 만들고 싶지 않기 때문에 새로운 () 연산자가 아닌 메인 클래스를 만들어야합니다.

위의 코드는 작동하지 않지만 응용 프로그램조차 찾을 수 없습니다. 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);
        }
    }
}
도움이 되었습니까?

해결책

맞아, 다시 시작하겠습니다.

무슨 일이 일어나고 있는지 이해하려면 .NET과 Windows가 서로 어떻게 관련되어 있는지 이해해야합니다. .NET은 Windows에서 실행되고 창, 목록보기, 편집 상자 (표준 텍스트 상자의 Win32 이름)와 같은 많은 기본 Win32 개념을 랩합니다. 즉, 유효한 .NET 인스턴스의 텍스트 상자 또는 양식을 가질 수 있지만 해당 항목의 기본 Windows 버전 (Editbox 또는 Window)은 아직 없습니다. HandleCreated가 True 일 때 항목의 Windows 버전이 생성됩니다.

양식의 창이 생성되기 전에 로그 드 메소드가 호출되는 것으로 이어지기 때문에 문제가 발생합니다. 이것은 양식 인스턴스가 인스턴스화 된 후 시작하는 동안 어딘가에 어딘가에 있지만 창 핸들이 생성되기 전에 무언가가 logadd를 호출하려고합니다. logadd에 중단 점을 추가하면 해당 호출을 수행하는 작업을 볼 수 있어야합니다. 당신이 찾을 수있는 것은 실제로 실행중인 기본 인스턴스가 아니라 Logger 클래스에서 작성한 기본 인스턴스에서 호출이 이루어지고 있다는 것입니다. 로거 인스턴스가 표시되지 않으므로 창 핸들이 생성되지 않으므로 오류가 발생합니다.

응용 프로그램이 실행되는 일반적인 방법은 일반적으로 프로그램 클래스에 있고 메인이라고 불리는 시작 방법에서 Application.Run (new Main ())을 호출하는 것입니다. 이 메인 인스턴스를 가리려면 로거가 필요합니다.

양식의 인스턴스를 각각 고유 한 경고를받는 방법에는 여러 가지가 있지만 단순화를 위해 인스턴스를 메인 클래스 자체에서 노출시킬 수 있습니다. 예를 들어:

public partial class Main : Form
{
    private static Main mainFormForLogging;
    public static Main MainFormForLogging
    {
        get
        {
            return mainFormForLogging;
        }
    }

    public Main()
    {
        InitializeComponent();

        if (mainFormForLogging == null)
        {
            mainFormForLogging = this;
        }
    }

    protected void Dispose(bool disposing)
    {
         if (disposing)
         {
             if (this == mainFormForLogging)
             {
                mainFormForLogging = null;
             }
         }

         base.Dispose(disposing);
    }
}

다른 팁

과거에 다음 방법을 사용하여 이것을 해결했습니다.

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

부르다 invokeOnFormThread 호출 대신. 핸들이 이미 작성된 경우에만 양식의 스레드를 사용합니다. 그렇지 않으면 발신자의 스레드를 사용합니다.

이 오류가 발생하면 거의 항상 생성되기 전에 컨트롤이나 양식에 따라 행동하려고 시도했다는 것을 의미합니다.

Winforms에서 GUI 요소는 두 가지 반 독립적 인 삶을 가지고 있습니다. 메모리의 클래스와 운영 체제의 엔티티로서. 따라서 아직 생성되지 않은 .NET의 컨트롤을 참조 할 수 있습니다. "작성된 핸들"은 프로그램이 속성을 조작 할 수 있도록 OS의 컨트롤에 숫자를 할당하는 것을 말합니다.

이 경우 양식의로드 이벤트가 끝날 때 플래그를 설정하고 해당 플래그가 설정된 후 양식의 컨트롤을 조작하려고 시도하여 대부분의 오류를 제거 할 수 있습니다.

컴파일러 오류가 아닌 런타임 오류입니다.

"메인"양식은 시작을 시작하거나 호출하기 전에 표시되기 전에 (따라서 창 핸들이 생성 됨) 표시해야합니다.

이 상황에서 내가 일반적으로하는 일은 양식으로 남겨두고 호출을 시작하여 시작하거나 호출 해야하는지 확인하는 것입니다. InvokeRequired (MSDN을 확인)로 호출하여 테스트 할 수 있습니다.

우선, Loggin 클래스의 UpdateLog 메소드에서 logadddelegate 호출을 제거 할 것입니다. 로그를 추가하기 위해 양식을 직접 호출하십시오. 그렇게 :

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 ()"에 전화를 추가하십시오. 기본 양식의 두 번째 사본이 나타나면 문제는 로깅 클래스가 양식의 '인스턴스'를 참조하지 않는다는 것입니다.

수업을 '청사진'으로 생각하십시오. 클래스의 각 인스턴스 ( 'New'라는 단어로 만든)는 청사진에서 만든 또 다른 객체입니다. 두 객체 (이 경우 두 가지 주요 형태)가 동일한 청사진을 공유한다고해서 상호 교환 적으로 사용할 수 있다는 의미는 아닙니다. 이 경우 이미 기본 형식이 있으며 '재사용'을 원합니다. 당신은 시도 할 수 있습니다:

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

현재 가지고있는 대신 로그 기능 내부. 차이점은 Application.openforms.ftype ()에 대한 호출이 먼저 응용 프로그램으로 이동하여보고있는 실제 기본 형식을 검색하고 (기술적으로는 첫 번째 인스턴스를 검색하고) 직접 형태.

도움이 되었기를 바랍니다.

이것은 다른 사람이 이것을 따라 잡는 경우를 대비하여 도움이됩니다. 내 문제 : vb.net : "창 손잡이가 생성 될 때까지 컨트롤에서 호출 또는 시작 할 수 없습니다." 이벤트의 핸들러가있는 양식을 닫았다.

내가 한 일 : 양식을 닫을 때 모든 핸들러를 제거하고 양식을 열 때 다시 할당했습니다. 문제를 해결했습니다.

logadddelegate (메시지);

Form_load 이벤트가 제기되기 전에 이것을 부르고 있다고 생각합니다. 로깅을 호출하기 전에 LogAddDelegate (...)를 호출하기 전에 양식이로드 될 때까지 코드를 수정하십시오. UPDATELOG ()

이것이 당신의 정확한 코드입니까? 당신은 전화하고 있습니다 this.Log.Items.Add(message); ADD (String) 메소드에서는 로깅 클래스를 로깅이 아닌 로깅이라고합니다. 아마도 로그라는 다른 양식이 있습니까? ADD 메소드를 호출 할 때 해당 양식이 작성되지 않은 경우이 예외가 발생합니다.

나는 찾았다 InvokeRequired 신뢰할 수 없으므로 단순히 사용합니다

if (!this.IsHandleCreated)
{
    this.CreateHandle();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top