데스크톱 응용 프로그램에서 창 위치를 저장하고 싶다는 클라이언트의 요구가 있었습니다.
그러나 구현하는 것이 큰 골칫거리 입니다.
예를들어 최대화를 하면 최대화하기 직전의 윈도우의 위치와 크기도 보존 해두지 않으면 안된다거나
세세한 동작까지 신경쓰면 여간 일이 많은게 아닙니다.
(+귀찮음)
조금 찾아 본 결과 MSDN에 해당 소스 코드가 있었기에
이를 기초로
Window창 위치의 보존&복원 기능을 구현 해보고자 합니다.
그전에 WPF도 어찌되었든 Window에서 움직이므로
.NetF FrameWork의 네이티브 라이브러리를 참조할 필요가 있습니다.
네이티브 라이브러리 기능을 호출하는 이것을 P/Invoke (Platform Invoke : 플랫폼 호출)이라고합니다.
public class NativeMethods { [DllImport("user32.dll")] public static extern bool SetWindowPlacement( IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl); [DllImport("user32.dll")] public static extern bool GetWindowPlacement( IntPtr hWnd, out WINDOWPLACEMENT lpwndpl); } [Serializable] [StructLayout(LayoutKind.Sequential)] public struct WINDOWPLACEMENT { public int length; public int flags; public SW showCmd; public POINT minPosition; public POINT maxPosition; public RECT normalPosition; } [Serializable] [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; public POINT(int x, int y) { this.X = x; this.Y = y; } } [Serializable] [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; public RECT(int left, int top, int right, int bottom) { this.Left = left; this.Top = top; this.Right = right; this.Bottom = bottom; } } public enum SW { HIDE = 0, SHOWNORMAL = 1, SHOWMINIMIZED = 2, SHOWMAXIMIZED = 3, SHOWNOACTIVATE = 4, SHOW = 5, MINIMIZE = 6, SHOWMINNOACTIVE = 7, SHOWNA = 8, RESTORE = 9, SHOWDEFAULT = 10, }
WINDOWPLACEMENT structure 구조체에 윈도우의 창 위치, 사이즈, 상태를 넣어 둘 수 있게 합니다.
그럼 이제 저장을 해야 하는데
MSDN 샘플 에서는 Settings.settings를 쓰고 있습니다.
근데 이러면 재미 없으니까 ^^;
보존 방법을 외부에서 설정 할 수 있도록 하겠습니다.
public interface IWindowSettings { WINDOWPLACEMENT? Placement { get; set; } void Reload(); void Save(); } public class WindowSettings : ApplicationSettingsBase, IWindowSettings { public WindowSettings(Window window) : base(window.GetType().FullName) { } [UserScopedSetting] public WINDOWPLACEMENT? Placement { get { return this["Placement"] != null ? (WINDOWPLACEMENT?)(WINDOWPLACEMENT)this["Placement"] : null; } set { this["Placement"] = value; } } }
그럼 이제 대략 준비는 끝났고
Window창이 자동적으로 보존・복원 되도록 합니다.
public class RestorableWindow : Window { #region WindowSettings 의존관계 프로퍼티 public IWindowSettings WindowSettings { get { return (IWindowSettings)this.GetValue(WindowSettingsProperty); } set { this.SetValue(WindowSettingsProperty, value); } } public static readonly DependencyProperty WindowSettingsProperty = DependencyProperty.Register("WindowSettings", typeof(IWindowSettings), typeof(RestorableWindow), new UIPropertyMetadata(null)); #endregion protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); // 외부에서 윈도의 복원 설정이 없을 경우 기본 구현을 사용 if (this.WindowSettings == null) { this.WindowSettings = new WindowSettings(this); } this.WindowSettings.Reload(); if (this.WindowSettings.Placement.HasValue) { var hwnd = new WindowInteropHelper(this).Handle; var placement = this.WindowSettings.Placement.Value; placement.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT)); placement.flags = 0; placement.showCmd = (placement.showCmd == SW.SHOWMINIMIZED) ? SW.SHOWNORMAL : placement.showCmd; NativeMethods.SetWindowPlacement(hwnd, ref placement); } } protected override void OnClosing(CancelEventArgs e) { base.OnClosing(e); if (!e.Cancel) { WINDOWPLACEMENT placement; var hwnd = new WindowInteropHelper(this).Handle; NativeMethods.GetWindowPlacement(hwnd, out placement); this.WindowSettings.Placement = placement; this.WindowSettings.Save(); } } }
WindowSettings 의존관계 프로퍼티는 창 위치의 보존・복원 수단을 외부에서주기위한 것입니다.
아무것도 지정하지 않으면 (= null) ApplicationSettingsBase를 사용한 기본 구현됩니다.
그리고 P/Invoke시는 SourceInitiazlized이벤트(창을 핸들링 할 수 있는 타이밍)에서
구성 정보를 복원하고 SetWindowPlacement 함수에서 윈도우의 위치를 설정합니다.
WINDOWPLACEMENT의 length 멤버는 반드시 sizeof(WINDOWPLACEMENT)가 설정되어 있어야합니다 (안 그러면 실패합니다).
flags는 딱히 0으로 해도 상관없습니다.
showCmd에는 복원 된 값이 SW_SHOWMINIMIZED (최소화 상태) 인 경우,
즉 지난번 시작할 때 최소화 된 채 종료 한 경우, SW_SHOWNORMAL (표준 상태)에서 표시하는 처리를 추가합니다.
마찬가지로, 윈도우가 닫히기 직전에하고 취소되지 않은 경우 GetWindowPlacement 함수에서 현재 윈도우 상태를 검색하고 저장합니다.
설정 파일은 %UserProfile%\AppData\Local\프로젝트명에 user.config파일에 저장됩니다.
'프로그래밍_Programing > C#' 카테고리의 다른 글
프린터 용지함 설정하기 (0) | 2017.02.15 |
---|---|
[번외] TortoiseSVN log export 했을 때 문자깨짐 문제 (2) | 2016.12.16 |
무엇이 다른가? WPF, WinRT, UWP(Universal Windows Platform) (1) | 2016.12.16 |