2014-09-18 5 views
9

다른 질문에서 this answer을 읽는 동안 나는 다음 코드가 UI를 잠그고 어떤 움직임도 일으키지 않을 것이라고 100 % 확신했습니다. 코멘트에왜 양식이 잠기지 않습니까?

private void button1_Click(object sender, EventArgs e) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     this.Left += 10; 
     System.Threading.Thread.Sleep(75); 
     this.Left -= 10; 
     System.Threading.Thread.Sleep(75); 
    } 
} 

나는 여러 다른 작동하지 것이라고 말했다하지만 영업 이익은했고, 우리가 시도해야한다고 주장했다. 새로운 Winforms 프로젝트를 만들고 단추를 추가 한 다음 위의 코드를 클릭하여 이벤트 처리기에 넣으면 양식이 실제로 흔들 렸습니다.

메시지 펌프가이 방법으로 차단되고 OnPaint가 양식이나 하위 컨트롤에서 호출되어서는 안되는 경우 양식 이동 방법은 어떻게됩니까?

+1

. 여전히 나쁜 생각입니다. – SLaks

+0

@SLaks 나는 그것이 좋은 생각이라는 것을 전혀 말하지 않고있다. 나는이 일을하게하는 도대체 무슨 일이 일어나고 있는지 알고 싶다. –

+2

어딘가에 'DoEvents'또는 일부 도덕적으로 상응하는 것이있을 수 있습니다. – Servy

답변

10

에어로가. Windows는 더 이상 비디오 프레임 버퍼에 직접 렌더링하지 않으며 메모리로 렌더링합니다. 비트 맵을 생각해보십시오. 그런 다음 DWM 프로세스는 이러한 비트 맵을 합성하여 버퍼에 블릿합니다. 이것은 여러 가지 창 그림 유물을 해결합니다. 가장 불명예스러운 창은 하나의 창을 다른 창으로 이동할 때 뒤에 남겨 두는 "흔적"이었을 것입니다. 어떤 프로세스를 소유 했든간에 하단 창은 공개 된 픽셀을 따라 잡고 다시 칠해 야했습니다. 시간이 지나면 도색되지 않은 픽셀이 보입니다. 작업 표시 줄 버튼 위에 마우스를 가져갈 때 볼 수있는 라이브 축소판, 크기에 맞게 축소 된 비트 맵 복사본 등 다른 특수 효과도 사용할 수 있습니다. 그리고 에어로 픽 (Aero Peek)은 비트 맵을 투영 한 것입니다. Vista와 Win7의 유리. 그리고 Store 앱이 Win8에 표시되는 특별한 "화면". 그리고 화면을 터치하면 보이는 표시가 나타납니다.

또한이 코드에도 영향을 미치기 때문에 이제는 비트 위치가 다른 위치로 바뀝니다. 원래 비트 맵은 그대로 유지되며 다시 칠할 필요가 없습니다.

XP 또는 Aero가 꺼진 상태에서이 방법을 사용하지 마십시오.

+0

당신이'이 말에 영향을 미친다 '고 말하면 나는 당신이 한 마디도 빠뜨린 것 같지만 어떤 단어인지 모른다. – Servy

+0

이것은 나의 첫 번째 생각이기도하지만, Windows 2000 및 XP에서 거의 동일한 코드를 실행하는 독특한 기억이 있습니다. 고스트 현상이나 찢어짐 현상 등의 명백한 문제는 없었습니다. 응용 프로그램이 응답하지 않을 것이라고 확신하지만 실제로는 문제가 아닙니다. 앞뒤로 흔들리는 동안 아무도 양식을 클릭하지 않으려 고합니다. 에어로의 유무에 관계없이 창 관리자는 에어로를 페인트합니다. –

1

CoroutinesFibers으로 인해 가능합니다.

스레드는 운영 체제 스케줄러가 독립적으로 관리 할 수있는 프로그래밍 된 명령어의 최소 시퀀스이지만 단일 스레드를 공유하는 응용 프로그램 내에 coroutine이 존재할 수 있습니다. 즉, 하나의 루틴은 다른 루틴이 실행되는 동안 해당 트랙에서 멈출 수 있고, 중단 된 지점에서 다시 같은 스레드 내에서 재개 할 수 있습니다.

외관상으로 무해한 속성을 설정했을 때 우리가 상상했던 것보다 훨씬 더 많은 일이 발생했습니다. this.Leftthis.Right.

질문에서 코드 예제에 약간의 로깅을 추가하면이 문제가 발생할 수 있습니다. 또한 — 이후 아래 예제에서 Thread.Sleep(75) 호출을 제거하고 이전 지점에서 더 긴 수면을 추가했습니다. — 수면을 다른 함수로 가져 오는 것이 아니라 this.Leftthis.Right을 호출하는 것을 볼 수 있습니다. (또한, 여전히 잠이없는 형태를 흔들하는) :

protected override void WndProc(ref Message m) 
    { 
     if (_logWndProc) 
      listBox1.Items.Add(string.Format("WndProc on thread {0}", Thread.CurrentThread.ManagedThreadId)); 

     base.WndProc(ref m); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     listBox1.Items.Clear(); 
     _logWndProc = true; 
     Thread.Sleep(2000); 
     listBox1.Items.Add(string.Format("After sleep on thread {0} (see any WndProc logs before this line?!!!)", Thread.CurrentThread.ManagedThreadId)); 

     for (int i = 0; i < 5; i++) 
     { 
      listBox1.Items.Add(string.Format("Right {0} on thread {1}", i, Thread.CurrentThread.ManagedThreadId)); 
      this.Left += 10; 
      listBox1.Items.Add(string.Format("Left {0} on thread {1}", i, Thread.CurrentThread.ManagedThreadId)); 
      this.Left -= 10; 
     } 

     _logWndProc = false; 
    } 

    private bool _logWndProc = false; 

로그 : 양식은`Paint`을 발사하지 않고도 이동할 수 있습니다

enter image description here

관련 문제