2013-08-28 1 views
5

최근에 내 WPF 응용 프로그램에 "app bar"로 데스크탑 가장자리에 도킹 할 수있는 창을 추가했습니다. 도킹을 수행하는 데 사용하는 코드는 this에서 발생했습니다.App Bar Window가 도킹 위치에서 튀어 나온 다음 도킹 위치로 이동합니다.

프로그램에는이 창과 관련된 세 가지 사용자 설정이 정의되어 있습니다. 하나는 윈도우가 도킹 된 가장자리이고 다른 두 개는 Left & Top 속성의 값입니다. 아이디어는 창이 닫히거나 프로그램이 종료 될 때 프로그램이 다시 시작될 때 창이 같은 상태와 위치로 다시 열리는 것입니다.

내가 겪고있는 문제는 프로그램이 열리면 화면이 처음 임의의 위치에 표시된다는 것입니다 (윈도우가 생성 될 때 Windows에서 할당 된 좌표 일 것임). 도킹 된 위치. Trillian과 같은 앱 표시 줄 기능이있는 다른 프로그램은 처음부터 도킹 된 위치에 그려져 있습니다. 창문이 그렇게 움직이는 것을 보는 것은 약간 당황 스럽습니다. I는 this acrticle 판독으로 I는 윈도우가 활성화 SHAppBarrMessage 때, 또는 그 위치 및 크기 변화를 호출하는 기능을 추가 한

private void AppBarWindow_Activated(object sender, EventArgs e) { 
    if (Settings.Default.AppBarWindowEdge != ABEdge.None) { 
     AppBarFunctions.SendShellActivated(this); 
    } 
} 

private void AppBarWindow_Closing(object sender, CancelEventArgs e) { 
    Settings.Default.AppBarWindowLeft = Left; 
    Settings.Default.AppBarWindowTop = Top; 
    Settings.Default.Save(); 

    AppBarFunctions.SetAppBar(this, ABEdge.None); 

    // Other, app specific code . . . 
} 

private void AppBarWindow_LocationChanged(object sender, EventArgs e) { 
    if (Settings.Default.AppBarWindowEdge != ABEdge.None) { 
     AppBarFunctions.SendShellWindowPosChanged(this); 
    } 
} 

private void AppBarWindow_SourceInitialized(object sender, EventArgs e) { 
    if (Settings.Default.AppBarWindowEdge != ABEdge.None) { 
     SizeWindow(Settings.Default.AppBarWindowEdge == ABEdge.None ? ABEdge.Left : ABEdge.None); 
    } 
} 

private void AppBarWindow_SizeChanged(object sender, SizeChangedEventArgs e) { 
    if (Settings.Default.AppBarWindowEdge != ABEdge.None) { 
     AppBarFunctions.SendShellWindowPosChanged(this); 
    } 
} 

private void SizeWindow(ABEdge originalEdge) { 
    // App specific code to compute the window's size . . . 

    if (originalEdge != Settings.Default.AppBarWindowEdge) { 
     AppBarFunctions.SetAppBar(this, Settings.Default.AppBarWindowEdge); 
    } 

    Settings.Default.AppBarWindowLeft = Left; 
    Settings.Default.AppBarWindowTop = Top; 
    Settings.Default.Save(); 
} 

: 여기

창의 일부 코드이다. 통화가 동작에 아무런 영향을 미치지 않는 것 같아서 제거 할 수 있습니다.

은 내가 SourceInitializedLoading 이벤트가 창이 표시되기 전에 호출되지만 창 핸들 및 레이아웃 & 측정 패스 후 완료된 것을 알고있다. 그러나 AppBarFunctions.SetAppBar에 대한 호출이 만들어지기 전에 윈도우가 렌더링 된 것으로 나타났습니다. 따라서 이것이 나타나고 그 자리로 이동하는 것을 볼 수 있습니다.

LeftTop 속성을 창 생성자의 설정에 저장된 값으로 설정하여 창을 도킹 된 위치로 이동하려고했습니다. 그것도 작동하지 않았다. 사실, 창문이 도킹 된 위치에 처음으로 그려지기 시작한 다음 데스크톱 가장자리에서 멀리 떨어진 곳으로 이동 한 다음 다시 도킹 된 위치로 다시 이동하는 것이 더 나빴습니다.

시작시이 창을 도킹 된 위치에 나타나게하고 나중에 이동하지 못하게하려면 어떻게해야합니까?

편집 :

문제의 원인을 찾았습니다. 창 Dispatcher (UI 스레드)에서 DoResize 메서드에 대한 호출을 예약하기 바로 전에 ABSetPos 메서드의 클래스 코드에 주석이 있습니다. 그래서 분명히 WPF 또는 Windows 창에 예약되는 공간의 창 밖으로 이동

// This is done async, because WPF will send a resize after a new appbar is added. 
// if we size right away, WPFs resize comes last and overrides us. 

을, 나는 다음에 다시 이동 내 코드 & I에서 추적 점을 많이 추가 : 주석은 읽습니다. (코드의 주석에 언급 된) 이동이 일어날 때까지 윈도우가 렌더되지 않는다는 것을 알 수 있습니다. 윈도우가 렌더링 된 후, 코드에 의해 도킹 된 위치로 이동됩니다.

AppBarFunctions 클래스는 이미 셸의 메시지에 대한 wathcing에 대한 창 프로 시저 후크를 추가합니다. WM_WINDOWPOSCHANGED에 대한 검사를 추가하면 어떻게 든 메시지가 처리되지 않을 수 있습니까?또는 Windows/WPF에서 수행 한 이동에 대한 LeftTop 속성의 값을 변경할 수 있으므로 원하는대로 끝납니다.

답변

5

도킹 된 영역에서 창을 이동하지 못하게하는 방법을 발견했습니다. 기본적으로, 내가 사용하고있는 코드는 이미 Window Procedure Hook 메서드를 사용하여 ABN_* 알림 메시지를 감시합니다. 이 메소드에 코드를 추가하여 WM_WINDOWPOSCHANGING 메시지를 감시했습니다.

여기에 내가 쓴 코드는 다음과 같습니다

창을 쉘에 등록 가장자리 &에 도킹
public IntPtr WindowProcedureHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { 
    if (msg == (int) WinMessages.WM_WINDOWPOSCHANGING) { 
     if (IsDocked && !IsDragging) { 
      WindowPos pos = (WindowPos) Marshal.PtrToStructure(lParam, typeof(WindowPos)); 

      // Keep this window in its docked position. 
      pos.x = (int) DockedPosition.X; 
      pos.y = (int) DockedPosition.Y; 
      pos.cx = (int) DockedSize.Width; 
      pos.cy = (int) DockedSize.Height; 

      Marshal.StructureToPtr(pos, lParam, false); 
      handled = true; 
     } 

    } else if (msg == CallbackId) { 
     if (wParam.ToInt32() == (int) ABNotify.ABN_WINDOWPOSCHANGED) { 
      SetDockedPosition(Window, this, true); 
      handled = true; 
     } 
    } 
    return IntPtr.Zero; 
} 

, 그것은 SHAppBarMessage/ABM_SETPOS로 호출에서 반환 도킹 사각형을 기억합니다. 메서드가 WM_WINDOWPOSCHANGED 메시지를 받으면 창을 가장자리에 도킹했는지 여부를 확인하고 끌지 않습니다. 이 경우 WINDOWPOS 구조체를 관리되지 않는 메모리에서 관리되는 개체로 마샬링하고 & 위치의 크기를 도킹 된 위치 & 크기로 다시 설정하고 관리되지 않는 메모리로 다시 정렬합니다. 그런 다음 처리 된 값을 true & 종료로 설정합니다.

이 완벽하게 작동 &가 다시 거리의 도킹 위치 &에서 튀는에서 창을 유지합니다. 그리고 윈도우의 Dispatcher 스레드에서 도킹 위치로 이동을 예약 할 필요가 없습니다.