2011-03-10 4 views
1

System.Windows.Forms.Timer 클래스를 사용하고 나서 사용을 마치면 사용할 수 없습니다 .. Enabledfalse으로 설정하더라도 틱합니다. 코드에 어떤 문제가 있습니까? 여기에 예제가 있습니다 :타이머를 사용하지 않도록 설정하는 이유는 무엇입니까?

int counter = 0; 
private void timer1_Tick(object sender, EventArgs e) { 
    MessageBox.Show("Hello"); 
    counter++; 
    if (counter == 10){ 
     timer1.Enabled = false; 
    } 
} 
+0

여기서 '카운터'가 선언되었으며, 어떻게 나타 납니까? –

답변

7

이것은 MessageBox.Show() 호출에 의해 유도 된 것 미묘한 버그입니다. MessageBox는 메시지 루프를 펌핑하여 UI를 유지합니다. Tick ​​이벤트 핸들러는 이전 틱에서 이미 활성화되어 있더라도 다시 실행할 수 있습니다. 카운터 변수는 사용자가 [확인] 버튼을 클릭 할 때까지 증가하지 않습니다. 결과적으로 화면에는 메시지 상자가 채워지고 확인 단추를 10 번 클릭 할 때까지 멈추지 않습니다.

메시지 상자가 표시되는 전에 앞에 카운터를 늘려야합니다.수정 :

int counter = 0; 
private void timer1_Tick(object sender, EventArgs e) { 
    counter++; 
    if (counter > 10) timer1.Enabled = false; 
    else MessageBox.Show("Hello"); 
} 

이러한 종류의 문제는 DoEvents()가 그렇게 나쁜 평판을 얻은 이유이기도합니다. 메시지 루프에 의해 유도 된 재진입을 제대로 처리 할 수있는 코드를 작성하는 것은 꽤 어렵습니다. 코드가 이미 활성화되었음을 나타내는 부울 플래그를 계속 유지해야합니다. 어떤 문제를 해결할 수있는 또 다른 방법은 다음과 같습니다.

int counter = 0; 
bool showingBox = false; 

private void timer1_Tick(object sender, EventArgs e) { 
    if (showingBox) return; 
    showingBox = true; 
    try { 
     MessageBox.Show("Hello"); 
     counter++; 
     if (counter == 10) timer1.Enabled = false; 
    } 
    finally { 
     showingBox = false; 
    } 
} 

이제는 한 번에 하나의 메시지 상자 만 얻을 수 있습니다.

이 재진입 문제는 타이머에만 한정되어 있음을 언급해야합니다. 대화 상자에는 재진입 문제를 피하기위한 대응책이 필요하며 응용 프로그램의 모든 창을 사용할 수 없습니다. 이렇게하면 사용자가 기본 창을 닫거나 대화 상자를 다시 불러오는 버튼을 클릭하는 등의 작업을 할 수 없습니다. 둘 다 오히려 비참한 사고. 이는 '예기치 않은'Windows 알림의 대부분을 처리합니다. 기본적으로 사용자가 생성 한 모든 메시지입니다. 가장자리의 경우 이벤트 처리기에 UI 효과가있는 타이머 (WM_TIMER가 비활성화되지 않음)입니다.

+0

정말 고맙습니다. 하루 종일이 문제를 처리하고 있습니다! – Mathlight

1

timer1.Stop()은 어떨까요? 나는이 수업에 너무 익숙하지 않지만 빨리 찾아 보았다 : Timer Class

+3

'Stop'은'this.Enabled = false; '이외의 아무것도하지 않습니다. – Bobby

+0

가상 -1. 'Start 메서드를 호출하는 것은 Enabled를 true로 설정하는 것과 같습니다. 마찬가지로, Stop 메서드를 호출하는 것은 Enabled를 false로 설정하는 것과 같습니다. – Aliostad

+0

"Start 메서드를 호출하는 것은 Enabled를 true로 설정하는 것과 같습니다. 마찬가지로 Stop 메서드를 호출하는 것은 Enabled를 false로 설정하는 것과 같습니다." 귀하의 링크 – Andrey

1

그것은 나를 위해 일하고있다. 폼에 타이머를 놓고 버튼 클릭시 timer1.start()를 호출하고 tick 이벤트와 해당 작업에 다음 코드를 추가합니다.

int i = 0; 
private void timer1_Tick(object sender, EventArgs e) 
{ 
    i++; 
    this.Text = i.ToString(); 
    if (i == 10) 
    { 
     timer1.Enabled = false; 
    } 
} 

당신은 중지를 호출해야합니다. 사용자까지 MessageBox.Show 블록 확인을 누르면 때문에

int counter = 0; 
private void timer1_Tick(object sender, EventArgs e) { 
    MessageBox.Show("Hello"); 
    counter++; 
    if (counter == 10){ 
     timer1.Stop(); 
     timer1.Dispose(); 
     timer1 = null; 
    } 
} 
+4

"Stop 메서드를 호출하는 것은 Enabled를 false로 설정하는 것과 같습니다." – Andrey

+0

당신은 마법의'MessageBox' 즉, 까다로운 (명백하지는 않지만) 부분을 삭제했습니다. –

+0

@ Albin Sunnanbo : 작은 간격으로 정말 자극적입니다. – Anuraj

1

이 시도.
MessageBox 아래의 코드는 10 개의 OK 버튼을 누를 때까지 실행되지 않습니다.
그러나 실행이 차단 된 경우에도 타이머가 계속 실행됩니다.

내가 MessageBox 여기 범인입니다 확신

int counter = 0; 
private void timer1_Tick(object sender, EventArgs e) { 
    counter++; 
    if (counter == 10){ 
     timer1.Enabled = false; 
    } 
    MessageBox.Show("Hello"); 
} 

가 (단지 메시지 박스를 이동)이 코드

+1

우리는 참조 null을 만들었지 만 객체 자체는 어떨까요? 아직도 살아있다. –

+0

아니, 더 이상 존재하지 않을 것이다. – JAiro

2

그것은이다

int i = 0; 
private void timer1_Tick(object sender, EventArgs e) 
{ 
    i++; 
    if (i == 10) 
    { 
     timer1.Stop(); 
    } 
} 
+0

자체는 mbx가 아닙니다. 만약 사용자 인터페이스 코드가 없다면 이벤트가 멈추지 않을 것입니다. –

+1

위의 코드를 사용하여 MessageBox를'Console.WriteLine'으로 대체하면 10 회 반복 된 후에 멈 춥니 다. 코드에 뭔가 다른 것이 있어야합니다. 더 많은 코드를 보여줘야합니다. –

1

을보십시오. 타이머 처리기에 짧은 실행 간격을 사용하면 실행이 겹치는 경우 잠재적으로 코드가 바람직하지 않게 작동 할 수 있습니다.

이 경우 처리기가 실행되고 MessageBox가 표시되어 사용자가 프롬프트를 승인 할 때까지 현재 범위의 실행이 중지되고 핸들러가 다시 시작되어 다른 프롬프트가 표시됩니다 , 그리고 다른, 등등. 이 시점에서 우리는 입력을 기다리는 MessageBox을 여러 개 가지고 있지만 counter은 한 번 증가하지 않았습니다. 프롬프트에서 '확인'을 클릭하면 counter이 원하는대로 증가하지만이 시점에서 표시되는 프롬프트 수를 나타내는 값이 아닌 1 값을 갖습니다. 즉, 사용자가 적어도 10 프롬프트에서 '확인'을 클릭 할 때까지 더 많은 시간이 지나면 다른 프롬프트가 표시됩니다.

프로세스가 동시 실행을 방지하기 위해 이미 진행되어있는 경우가 실행을 억제 시도 할 수 :

private readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); 

int counter = 0; 
private void timer1_Tick(object sender, EventArgs e) 
{ 
    if (Locker.TryEnterWriteLock(0)) 
    { 
     try 
     { 
      MessageBox.Show("Hello"); 
      Counter++; 
      if (Counter == 10) 
      { 
       Timer.Enabled = false; 
      } 
     } 
     catch { } 
     finally 
     { 
      Locker.ExitWriteLock(); 
     } 
    } 
} 
관련 문제