2012-02-03 5 views
2

기본 C# 문제.C# Button - 여러 메서드 호출

두 개의 비활성화 된 텍스트 상자가 내 양식과 단추 하나에 있습니다. 이 버튼은과 같이 현재 :

private void start_Click(object sender, EventArgs e) 
    { 
     this.two(); 
     this.hold(); 
     this.one() 
    } 

당신이 그것을과 같이 세 가지 다른 방법을 호출 볼 수 있듯이 :

  • "두"- 블랙, 두 텍스트 상자에 BackColor를 만듭니다.
  • "one"- 상자 중 하나를 BackColor Black으로 만듭니다.
  • "hold"
    • "System.Threading.Thread.Sleep (1000);" 잠시 동안 프로그램을 일시 중지합니다.
    • 두 텍스트 상자의 backcolour를 모두 흰색으로 변경합니다.

I가 발생하고 문제는 프로그램이 처음 호출을 건너 뛸 것입니다. 그리고 잠시 동안 프로그램을 누르고 텍스트 상자 하나를 검정색으로 변경하십시오.

도움 주셔서 감사합니다.

+0

; 하나의 끝에. 또한 this.two()라는 버튼 호출 만 있으면 두 상자를 검정으로 바꿀 수 있습니까? – cost

+0

서버 측에서 모든 작업을 수행하고 있고 모든 메소드 호출이 완료되면 페이지에서 비헤이비어를 봅니다. 그래서 당신이 생각하는 행동은 예상 된 것 같아요. 전화를 "2"로 건너 뛰는 지 살펴 보았습니까? – AJP

+0

KeithS의 말을 듣고 다음을 읽으십시오 : http://en.wikipedia.org/wiki/Message_loop_in_Microsoft_Windows –

답변

3

아마도이 코드는 응용 프로그램의 주 스레드에서 실행 중이며 텍스트 상자의 색을 변경 한 후에 다시 그리는 명령과 같은 Windows GUI 메시지에 응답해야합니다. 프로그램은 현재이 이벤트 처리기가 완전히 실행될 때까지이 메시지를 처리하지 않습니다.이 이벤트 처리기는 하나의 텍스트 상자 만 검정색입니다.

Application.DoEvents()는이 핸들러를 중단하고 진행하기 전에 대기중인 메시지를 GUI에서 처리하도록하여 문제를 해결합니다. 이 작업을 수행하는 또 다른 방법은 BackgroundWorker에서이 코드를 실행하는 것입니다. BackgroundWorker는 별도의 처리 스레드를 사용하여 GUI 스레드가 텍스트 상자를 다시 칠하도록하고 Sleep() 명령으로 GUI 스레드를 차단하지 않도록합니다. 일반적으로 Application.DoEvents()는 현재 스레드가 완료되지 않은 상태에서 다른 이벤트 처리기를 강제 실행하여 예기치 않은 결과를 초래할 수 있으므로 다중 스레드 접근 방식을 사용하는 것이 좋습니다 (예 : 예외를 throw하는 다른 이벤트 처리기를 호출하면 방해하지 않은 Application.DoEvents 호출을 통해 던져 버리십시오. 실제로 문제가 없었습니다.)

2

이 시도 :

private void start_Click(object sender, EventArgs e) 
{ 
    this.two(); 
    Application.DoEvents(); 
    this.hold(); 
    this.one(); 
} 

DoEvents();를 호출하면 윈도우가 오히려 완료 될 때까지 기다리지 않고, 클릭 처리기의 중간에 다시 칠 수 있습니다.

편집 :이 답변에 대한 의견을 읽으십시오 ... 이와 같은 차단 작업을 수행하는 것은 "나쁜 습관"이라는 것을 알 수 있습니다.

+2

Yuck. 초보자에게 불량 프로그래밍 실습을 권장하지 않는 이유 (예 : 메시지 펌프 모델)가 전혀없는 것보다 나쁜 것입니다. -1 –

+0

@EdS. ㅎ ... 나는 그것을 홍보하는 것이 아니라, 설교하는 것이 나의 직업이 아니다. 나는 명시된 문제에 대한 빠른 해결책을 제시하기 위해 여기에있다. – Fosco

+0

나는 그것이 설교라고 생각하지 않는다. 우리는 분명히 뒤에서 무슨 일이 일어나고 있는지 알지 못하는 초보자가 있습니다. 이제 우리는 코드를 처음부터 올바르게 작성하는 대신 코드 전체에'DoEvents' 호출을 뿌릴 초보자가 있습니다. 이것은 최고의 해킹이며 OP를 가르치지 않습니다. –

1

UI 스레드에서 Thread.Sleep을 실행 중이므로 양식이 자체를 업데이트하고 새 색상으로 다시 칠할 기회를 얻지 못합니다.

hold 앞에 Application.DoEvents 전화를 사용할 수 있습니다. 그러나 다른 사람들이 지적했듯이, 이것은 UI 스레드가 1 초 지연 동안 고정 된 상태 (그리고 사용자 활동에 응답하지 않음)로 남아있게합니다.

로직에 지연을 도입하는 가장 좋은 방법은 Timer을 사용하는 것입니다. 다음은 1 초 지연 후 two을 실행하는 몇 가지 샘플 코드입니다.

Timer timer = new Timer { Interval = 1000 }; 
timer.Tick += (sender, e) => 
{ 
    this.Invoke(new Action(two)); 
    timer.Stop(); 
    timer.Dispose(); 
}; 
timer.Start(); 
2

two에 전화를 생략하지 않습니다,하지만 당신은 Thread.Sleep에 전화로 UI 스레드를 차단하고 있기 때문에, UI는 결코 two의 효과를 보여주기 위해 새로 고침 할 수있는 기회가 없습니다.

private void start_Click(object sender, EventArgs e) 
{ 
    this.two() 
    Task.Factory.StartNew(() => this.hold()) 
       .ContinueWith(_ => this.one(), TaskScheduler.FromCurrentSynchronizationContext()); 
} 

그것은 (따라서 UI를 동결하지 않음) 새 스레드에서 hold를 실행 hold이 완료되면, 그것은 UI 스레드에서 two를 실행합니다 :

은 당신이 뭔가를 할 수 있습니다.

+0

이렇게하면 1 초 동안 스레드 풀 스레드가 차단되지 않습니까? 나는 이것이 대다수의 경우에 문제가되지 않을 것이라는 것을 알고 있지만, 동시에 여러 가지 지연이 있으면 스레드 풀이 고갈 될 수 있습니다. – Douglas

+0

@Douglas : 글쎄, 풀에서 스레드에 대해 오랜 작업을 수행 할 때마다 이런 일이 발생할 수 있습니다 ... 그렇다고해서 결코 ThreadPool에서 긴 작업을 수행 할 수 없다는 것을 의미하지는 않습니다. –

+0

하지만 대부분의 경우 그렇게해서는 안됩니다. TPL은 특별히 TaskCreationOptions.LongRunning 옵션을 도입하여 긴 작업 (대신에 전용 스레드 생성)으로 스레드 풀을 막지 않도록했습니다. 그리고 긴 수면은 아마도 같은 기능을 수행하는'Timer' 클래스를 가지고있을 때 스레드 풀 스레드를 낭비하지 않아야합니다. – Douglas

3

다른 언급처럼, UI 스레드가 디스플레이 새로 고침을 시작하기 전에 잠자기하기 시작했기 때문입니다.

UI 스레드에서 Thread.Sleep을 절대 호출하지 마십시오. 프로그램을 "차단"하여 사용자를 화나게 할 것입니다. Thread.Sleep이 필요한 작업이 있으면 새 스레드를 만들고 UI 스레드에서는 수행하지 마십시오.