2011-12-27 4 views
-1

스레드 및 스레드 우선 순위를 처리하는 다음 프로그램에서 작업하고 있습니다.C# Null 참조 예외

풍부한 텍스트 상자 (DisplayTextBox)와 두 개의 버튼 (앱 실행을위한 StartButton 및 앱 닫기를위한 ExitButton)을 포함하는 Windows 폼을 구성했습니다.

양식에서 여러 스레드를 만들고 차례로 실행하고 있습니다. 각 thread가 사용하는 메소드는 Threading 클래스에 있습니다. 해당 메서드는 PrintOnScreen()입니다.

이 메서드에서는 스레드 이름과 우선 순위를 StringBuilder 유형의 str에 추가합니다. 그런 다음 DisplayTextBox (Form.cs에 있음)에 str의 내용을 표시하려고합니다.

그러나 "NullReferenceException 처리되지 않았습니다 : 개체 참조가 개체의 인스턴스로 설정되지 않았습니다."오류가 발생합니다. 오류가 발생한 행은 다음과 같습니다.

DisplayTextBox.Text = Convert.ToString (str);

이 오류를 해결하는 데 도움을 주시기 바랍니다 수 있습니까? 감사. 당신의 도움에 대한 모든

편집

감사합니다. 이 문제를 해결하기 위해 PrintOnScreen 메서드를 Form.cs 클래스에 복사하고 Threading.cs를 삭제했습니다.

나중에 Anand가 제공 한 코드를 사용하여 t2.Join() 아래에 배치했습니다. 이제 그것은 매력처럼 작동합니다.

+0

어떤 개체가 null인지 아십니까? 이 질문에 대한 가능한 대답은 두 가지뿐입니다. 첫 번째는 ** DisplayTextBox입니다. ** 두 번째는 ** str **입니다. 물론 폼의 DisplayTextBox에 대한 참조를 전달하는 곳을 볼 수 없습니다. Thread1은 Form1을 상속하지만 Form1의 컨트롤을 참조하는 것은 아닙니다. –

+0

코드를 수정하고 ** DisplayTextBox **에 대한 참조를 전달하더라도 메인 UI 스레드가 아닌 별도의 스레드에서 컨트롤을 수정할 수 없으므로 텍스트 변경을 호출해야합니다. –

+0

여러 스레드에서 액세스하는 데이터에 대한 액세스를 실제로 동기화해야합니다. 예를 들어 두 스레드를 모두 동일한 StringBuilder 인스턴스에 쓰고 Threads 컬렉션을 반복합니다. – Jan

답변

3

문제가 양식의 생성자에서 발생합니다. DisplayText을 다시 로컬 멤버로 선언하므로 폼의 필드가 초기화되지 않습니다. 생성자를 다음과 같이 변경하십시오.

private void Form1_Load(object sender, EventArgs e) 
{ 
    DescTextBox.Visible = false; 
    DisplayTextBox = new RichTextBox(); 
    DisplayTextBox.Location = new Point(15, 31); 
    DisplayTextBox.Height = 258; 
    DisplayTextBox.Width = 303; 
    panel1.Controls.Add(DisplayTextBox); 
} 

예상대로 작동해야합니다.

편집 : 그러나 배경 작업자 스레드에서 UI 요소를 변경하려는 경우 얻을 수있는 문제에주의하십시오. 이 경우 invoke 패턴을 사용해야합니다.

1

주 응용 프로그램 스레드가 아닌 다른 스레드의 컨트롤과 통신 할 수 없습니다. 디스 패저를 사용해야합니다. 여기에서 찾아 보게한다 : http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx

편집
@Fischermaen을 - ㅎ,이 통지를하지 않았다하지만 여전히 때문에 그가 실패 쓴 라인의 작동하지 않습니다. 그는 여전히 비 메인 스레드에서 컨트롤

편집 2 개
관련 스레드에서 Text 속성을 설정하는 디스패처를 사용해야합니다 :
How to update the GUI from another thread in C#?
In WinForms, why can't you update UI controls from other threads?

+0

운영진에 대한 제안에 감사드립니다. 나는 그것을 시도하고 그것이 작동하는 경우 알려드립니다. 모두에게 감사 : – Joe

1

나는 간단한 콘솔 응용 프로그램에서이 시도 그리고 그것은 잘 작동했습니다. DisplayTextBox에 문제가 있습니다. 모든 컨트롤과 상호 작용하려면 UI 스레드 또는 Dispatcher를 사용해야합니다. 는 대신 사용

DisplayTextBox.Text = Convert.ToString(str); 

이 하나

Dispatcher.Invoke(DispatcherPriority.Normal, 
        new Action(
      delegate() 
      { 
       DisplayTextBox.Text = Convert.ToString(str); 
      } 
     )); 
+0

정확 하 게. 콘솔 응용 프로그램에서는 제대로 작동합니다. 그것이 내게주는 문제는 Windows app으로 변환하려고 할 때입니다. – Joe

+0

위의 코드를 사용해보십시오. 그것은 잘 작동합니다. – Anand

+0

코드를 붙여 넣으면 오류가 발생합니다. 'Dispatcher'이름이 현재 컨텍스트에 없습니다. – Joe

0

음, 당신의 스레딩 클래스에서 다음 코드를 사용합니다. 여기에서 볼 수는 없지만 문제가있는 이유 중 일부는 캡슐화가 부족하고 코드에서 수명 관리가 잘 못된다는 것입니다.

PrintOnScreen 메서드 내에서 str을 인스턴스화하고 더 나은 이름을 지정하면 멤버 변수가 될 필요가 없습니다. 변수를 공개 할 필요가 없습니다. 대신에, 공극을 갖는 결과

, 그것은 문자열 결과

예를 리턴 한 팁으로

SomeTextBox = PrintOnScreen(); // (GetThreadDetails might be a better name...) 

은 프리젠 테이션과 논리를 혼합하지 않습니다. UI 컨트롤은 소유하고있는 모든 것에서 철저하게 관리하십시오.

그리고

public SomeType SomeName; 

이 속성하고 그것이 짧은 형식의 경우에도, getter와 세터 제공하지 않는다

공공 SomeType의 SomeName {얻을; 설정;}

을 코드의 다른 비트가 하나 개 이상의 소유자가 있어야

Form1.SomeType = (SomeOtherType)someVar; // with appaling consequences. 

아무것도 같은 정말 어리석은 일을 할 수있는, 다른 경로를 파멸에 이르게.

PS str.ToString()은 Convert.ToString (str)보다 더 나은 옵션입니다.

0

글쎄, 당신이 달성하고자하는 것은 분명하지 않지만 문제는 기본 폼 스레딩 클래스가 컨트롤에 액세스하려고 할 때로드되지 않는다는 것입니다 (윈도우 핸들이 아직 존재하지 않음).) 또한 이것은 스레드가 숨겨진 양식으로 출력하기 때문에 Form1 자체에서 아무 것도 볼 수없는 이유입니다 (표시되지 않음).

나는 SOReader에 의해 제기 된 스레드 액세스 문제를 해결하려고한다고 생각합니다. 이렇게하는 것은 적절한 방법이 아닙니다.