Как вы делаете стыковку AppBar (к краю экрана, например WinAmp) в WPF?

Есть ли какие-либо полные рекомендации по выполнению стыковки AppBar (например, блокировка к краю экрана) в WPF? Я понимаю, что есть вызовы InterOp, которые нужно сделать, но я ищу либо доказательство концепции, основанное на простой форме WPF, либо компонентную версию, которая может быть использована.

Связанные ресурсы:

  • http://www.codeproject.com/KB/dotnet/AppBar.aspx
  • http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/05c73c9c-e85d-4ecd-b9b6-4c714a65e72b/

Обратите внимание: этот вопрос собрал большое количество отзывов, а некоторые люди ниже сделали большие очки или исправления. Поэтому, хотя я буду хранить код здесь (и, возможно, обновить его), я также создал проект WpfAppBar для github . Не стесняйтесь отправлять запросы на тягу.

Этот же проект также построен в пакете wpfAppBar nuget


Я взял код из первой ссылки, указанной в вопросе ( http://www.codeproject.com/KB/dotnet/AppBar.aspx ), и изменил его, чтобы сделать две вещи:

  1. Работа с WPF
  2. Будьте «автономными» – если вы поместите этот единственный файл в свой проект, вы можете вызвать AppBarFunctions.SetAppBar (…) без каких-либо дополнительных изменений в окне.

Этот подход не создает базовый class.

Чтобы использовать, просто вызовите этот код из любого места в обычном wpf-окне (например, нажмите кнопку или инициализируйте). Обратите внимание, что вы не можете вызвать это до тех пор, пока ПОСЛЕ того, как окно не будет инициализировано, если HWND еще не создан (например, в конструкторе), произойдет ошибка.

Сделайте окно панелью объявлений:

AppBarFunctions.SetAppBar( this, ABEdge.Right ); 

Восстановите окно в обычном окне:

 AppBarFunctions.SetAppBar( this, ABEdge.None ); 

Вот полный код файла – обратите внимание, что вы захотите изменить пространство имен в строке 7 на что-то подходящее.

 using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.Windows.Threading; namespace AppBarApplication { public enum ABEdge : int { Left = 0, Top, Right, Bottom, None } internal static class AppBarFunctions { [StructLayout(LayoutKind.Sequential)] private struct RECT { public int left; public int top; public int right; public int bottom; } [StructLayout(LayoutKind.Sequential)] private struct APPBARDATA { public int cbSize; public IntPtr hWnd; public int uCallbackMessage; public int uEdge; public RECT rc; public IntPtr lParam; } private enum ABMsg : int { ABM_NEW = 0, ABM_REMOVE, ABM_QUERYPOS, ABM_SETPOS, ABM_GETSTATE, ABM_GETTASKBARPOS, ABM_ACTIVATE, ABM_GETAUTOHIDEBAR, ABM_SETAUTOHIDEBAR, ABM_WINDOWPOSCHANGED, ABM_SETSTATE } private enum ABNotify : int { ABN_STATECHANGE = 0, ABN_POSCHANGED, ABN_FULLSCREENAPP, ABN_WINDOWARRANGE } [DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)] private static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData); [DllImport("User32.dll", CharSet = CharSet.Auto)] private static extern int RegisterWindowMessage(string msg); private class RegisterInfo { public int CallbackId { get; set; } public bool IsRegistered { get; set; } public Window Window { get; set; } public ABEdge Edge { get; set; } public WindowStyle OriginalStyle { get; set; } public Point OriginalPosition { get; set; } public Size OriginalSize { get; set; } public ResizeMode OriginalResizeMode { get; set; } public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == CallbackId) { if (wParam.ToInt32() == (int)ABNotify.ABN_POSCHANGED) { ABSetPos(Edge, Window); handled = true; } } return IntPtr.Zero; } } private static Dictionary s_RegisteredWindowInfo = new Dictionary(); private static RegisterInfo GetRegisterInfo(Window appbarWindow) { RegisterInfo reg; if( s_RegisteredWindowInfo.ContainsKey(appbarWindow)) { reg = s_RegisteredWindowInfo[appbarWindow]; } else { reg = new RegisterInfo() { CallbackId = 0, Window = appbarWindow, IsRegistered = false, Edge = ABEdge.Top, OriginalStyle = appbarWindow.WindowStyle, OriginalPosition =new Point( appbarWindow.Left, appbarWindow.Top), OriginalSize = new Size( appbarWindow.ActualWidth, appbarWindow.ActualHeight), OriginalResizeMode = appbarWindow.ResizeMode, }; s_RegisteredWindowInfo.Add(appbarWindow, reg); } return reg; } private static void RestoreWindow(Window appbarWindow) { RegisterInfo info = GetRegisterInfo(appbarWindow); appbarWindow.WindowStyle = info.OriginalStyle; appbarWindow.ResizeMode = info.OriginalResizeMode; appbarWindow.Topmost = false; Rect rect = new Rect(info.OriginalPosition.X, info.OriginalPosition.Y, info.OriginalSize.Width, info.OriginalSize.Height); appbarWindow.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new ResizeDelegate(DoResize), appbarWindow, rect); } public static void SetAppBar(Window appbarWindow, ABEdge edge) { RegisterInfo info = GetRegisterInfo(appbarWindow); info.Edge = edge; APPBARDATA abd = new APPBARDATA(); abd.cbSize = Marshal.SizeOf(abd); abd.hWnd = new WindowInteropHelper(appbarWindow).Handle; if( edge == ABEdge.None) { if( info.IsRegistered) { SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref abd); info.IsRegistered = false; } RestoreWindow(appbarWindow); return; } if (!info.IsRegistered) { info.IsRegistered = true; info.CallbackId = RegisterWindowMessage("AppBarMessage"); abd.uCallbackMessage = info.CallbackId; uint ret = SHAppBarMessage((int)ABMsg.ABM_NEW, ref abd); HwndSource source = HwndSource.FromHwnd(abd.hWnd); source.AddHook(new HwndSourceHook(info.WndProc)); } appbarWindow.WindowStyle = WindowStyle.None; appbarWindow.ResizeMode = ResizeMode.NoResize; appbarWindow.Topmost = true; ABSetPos(info.Edge, appbarWindow); } private delegate void ResizeDelegate(Window appbarWindow, Rect rect); private static void DoResize(Window appbarWindow, Rect rect) { appbarWindow.Width = rect.Width; appbarWindow.Height = rect.Height; appbarWindow.Top = rect.Top; appbarWindow.Left = rect.Left; } private static void ABSetPos(ABEdge edge, Window appbarWindow) { APPBARDATA barData = new APPBARDATA(); barData.cbSize = Marshal.SizeOf(barData); barData.hWnd = new WindowInteropHelper(appbarWindow).Handle; barData.uEdge = (int)edge; if (barData.uEdge == (int)ABEdge.Left || barData.uEdge == (int)ABEdge.Right) { barData.rc.top = 0; barData.rc.bottom = (int)SystemParameters.PrimaryScreenHeight; if (barData.uEdge == (int)ABEdge.Left) { barData.rc.left = 0; barData.rc.right = (int)Math.Round(appbarWindow.ActualWidth); } else { barData.rc.right = (int)SystemParameters.PrimaryScreenWidth; barData.rc.left = barData.rc.right - (int)Math.Round(appbarWindow.ActualWidth); } } else { barData.rc.left = 0; barData.rc.right = (int)SystemParameters.PrimaryScreenWidth; if (barData.uEdge == (int)ABEdge.Top) { barData.rc.top = 0; barData.rc.bottom = (int)Math.Round(appbarWindow.ActualHeight); } else { barData.rc.bottom = (int)SystemParameters.PrimaryScreenHeight; barData.rc.top = barData.rc.bottom - (int)Math.Round(appbarWindow.ActualHeight); } } SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref barData); SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref barData); Rect rect = new Rect((double)barData.rc.left, (double)barData.rc.top, (double)(barData.rc.right - barData.rc.left), (double)(barData.rc.bottom - barData.rc.top)); //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. appbarWindow.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new ResizeDelegate(DoResize), appbarWindow, rect); } } } 

Очень рад, что нашел этот вопрос. Выше class действительно полезен, но не полностью охватывает все основы реализации AppBar.

Чтобы полностью реализовать все поведение AppBar (справиться с полноэкранными приложениями и т. Д.), Вам также захочется прочитать эту статью MSDN.

http://msdn.microsoft.com/en-us/library/bb776821.aspx

Извините за мой английский … Вот решение Филиппа Рика с некоторыми исправлениями. Он корректно работает с изменениями позиции и размера панели задач.

 using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.Windows.Threading; namespace wpf_appbar { public enum ABEdge : int { Left, Top, Right, Bottom, None } internal static class AppBarFunctions { [StructLayout(LayoutKind.Sequential)] private struct RECT { public int Left; public int Top; public int Right; public int Bottom; public RECT(Rect r) { Left = (int)r.Left; Right = (int)r.Right; Top = (int)r.Top; Bottom = (int)r.Bottom; } public static bool operator ==(RECT r1, RECT r2) { return r1.Bottom == r2.Bottom && r1.Left == r2.Left && r1.Right == r2.Right && r1.Top == r2.Top; } public static bool operator !=(RECT r1, RECT r2) { return !(r1 == r2); } public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); } } [StructLayout(LayoutKind.Sequential)] private struct APPBARDATA { public int cbSize; public IntPtr hWnd; public int uCallbackMessage; public int uEdge; public RECT rc; public IntPtr lParam; } private enum ABMsg : int { ABM_NEW = 0, ABM_REMOVE, ABM_QUERYPOS, ABM_SETPOS, ABM_GETSTATE, ABM_GETTASKBARPOS, ABM_ACTIVATE, ABM_GETAUTOHIDEBAR, ABM_SETAUTOHIDEBAR, ABM_WINDOWPOSCHANGED, ABM_SETSTATE } private enum ABNotify : int { ABN_STATECHANGE = 0, ABN_POSCHANGED, ABN_FULLSCREENAPP, ABN_WINDOWARRANGE } private enum TaskBarPosition : int { Left, Top, Right, Bottom } [StructLayout(LayoutKind.Sequential)] class TaskBar { public TaskBarPosition Position; public TaskBarPosition PreviousPosition; public RECT Rectangle; public RECT PreviousRectangle; public int Width; public int PreviousWidth; public int Height; public int PreviousHeight; public TaskBar() { Refresh(); } public void Refresh() { APPBARDATA msgData = new APPBARDATA(); msgData.cbSize = Marshal.SizeOf(msgData); SHAppBarMessage((int)ABMsg.ABM_GETTASKBARPOS, ref msgData); PreviousPosition = Position; PreviousRectangle = Rectangle; PreviousHeight = Height; PreviousWidth = Width; Rectangle = msgData.rc; Width = Rectangle.Right - Rectangle.Left; Height = Rectangle.Bottom - Rectangle.Top; int h = (int)SystemParameters.PrimaryScreenHeight; int w = (int)SystemParameters.PrimaryScreenWidth; if (Rectangle.Bottom == h && Rectangle.Top != 0) Position = TaskBarPosition.Bottom; else if (Rectangle.Top == 0 && Rectangle.Bottom != h) Position = TaskBarPosition.Top; else if (Rectangle.Right == w && Rectangle.Left != 0) Position = TaskBarPosition.Right; else if (Rectangle.Left == 0 && Rectangle.Right != w) Position = TaskBarPosition.Left; } } [DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)] private static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData); [DllImport("User32.dll", CharSet = CharSet.Auto)] private static extern int RegisterWindowMessage(string msg); private class RegisterInfo { public int CallbackId { get; set; } public bool IsRegistered { get; set; } public Window Window { get; set; } public ABEdge Edge { get; set; } public ABEdge PreviousEdge { get; set; } public WindowStyle OriginalStyle { get; set; } public Point OriginalPosition { get; set; } public Size OriginalSize { get; set; } public ResizeMode OriginalResizeMode { get; set; } public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == CallbackId) { if (wParam.ToInt32() == (int)ABNotify.ABN_POSCHANGED) { PreviousEdge = Edge; ABSetPos(Edge, PreviousEdge, Window); handled = true; } } return IntPtr.Zero; } } private static Dictionary s_RegisteredWindowInfo = new Dictionary(); private static RegisterInfo GetRegisterInfo(Window appbarWindow) { RegisterInfo reg; if (s_RegisteredWindowInfo.ContainsKey(appbarWindow)) { reg = s_RegisteredWindowInfo[appbarWindow]; } else { reg = new RegisterInfo() { CallbackId = 0, Window = appbarWindow, IsRegistered = false, Edge = ABEdge.None, PreviousEdge = ABEdge.None, OriginalStyle = appbarWindow.WindowStyle, OriginalPosition = new Point(appbarWindow.Left, appbarWindow.Top), OriginalSize = new Size(appbarWindow.ActualWidth, appbarWindow.ActualHeight), OriginalResizeMode = appbarWindow.ResizeMode, }; s_RegisteredWindowInfo.Add(appbarWindow, reg); } return reg; } private static void RestoreWindow(Window appbarWindow) { RegisterInfo info = GetRegisterInfo(appbarWindow); appbarWindow.WindowStyle = info.OriginalStyle; appbarWindow.ResizeMode = info.OriginalResizeMode; appbarWindow.Topmost = false; Rect rect = new Rect(info.OriginalPosition.X, info.OriginalPosition.Y, info.OriginalSize.Width, info.OriginalSize.Height); appbarWindow.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new ResizeDelegate(DoResize), appbarWindow, rect); } public static void SetAppBar(Window appbarWindow, ABEdge edge) { RegisterInfo info = GetRegisterInfo(appbarWindow); info.Edge = edge; APPBARDATA abd = new APPBARDATA(); abd.cbSize = Marshal.SizeOf(abd); abd.hWnd = new WindowInteropHelper(appbarWindow).Handle; if (edge == ABEdge.None) { if (info.IsRegistered) { SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref abd); info.IsRegistered = false; } RestoreWindow(appbarWindow); info.PreviousEdge = info.Edge; return; } if (!info.IsRegistered) { info.IsRegistered = true; info.CallbackId = RegisterWindowMessage("AppBarMessage"); abd.uCallbackMessage = info.CallbackId; uint ret = SHAppBarMessage((int)ABMsg.ABM_NEW, ref abd); HwndSource source = HwndSource.FromHwnd(abd.hWnd); source.AddHook(new HwndSourceHook(info.WndProc)); } appbarWindow.WindowStyle = WindowStyle.None; appbarWindow.ResizeMode = ResizeMode.NoResize; appbarWindow.Topmost = true; ABSetPos(info.Edge, info.PreviousEdge, appbarWindow); } private delegate void ResizeDelegate(Window appbarWindow, Rect rect); private static void DoResize(Window appbarWindow, Rect rect) { appbarWindow.Width = rect.Width; appbarWindow.Height = rect.Height; appbarWindow.Top = rect.Top; appbarWindow.Left = rect.Left; } static TaskBar tb = new TaskBar(); private static void ABSetPos(ABEdge edge, ABEdge prevEdge, Window appbarWindow) { APPBARDATA barData = new APPBARDATA(); barData.cbSize = Marshal.SizeOf(barData); barData.hWnd = new WindowInteropHelper(appbarWindow).Handle; barData.uEdge = (int)edge; RECT wa = new RECT(SystemParameters.WorkArea); tb.Refresh(); switch (edge) { case ABEdge.Top: barData.rc.Left = wa.Left - (prevEdge == ABEdge.Left ? (int)Math.Round(appbarWindow.ActualWidth) : 0); barData.rc.Right = wa.Right + (prevEdge == ABEdge.Right ? (int)Math.Round(appbarWindow.ActualWidth) : 0); barData.rc.Top = wa.Top - (prevEdge == ABEdge.Top ? (int)Math.Round(appbarWindow.ActualHeight) : 0) - ((tb.Position != TaskBarPosition.Top && tb.PreviousPosition == TaskBarPosition.Top) ? tb.Height : 0) + ((tb.Position == TaskBarPosition.Top && tb.PreviousPosition != TaskBarPosition.Top) ? tb.Height : 0); barData.rc.Bottom = barData.rc.Top + (int)Math.Round(appbarWindow.ActualHeight); break; case ABEdge.Bottom: barData.rc.Left = wa.Left - (prevEdge == ABEdge.Left ? (int)Math.Round(appbarWindow.ActualWidth) : 0); barData.rc.Right = wa.Right + (prevEdge == ABEdge.Right ? (int)Math.Round(appbarWindow.ActualWidth) : 0); barData.rc.Bottom = wa.Bottom + (prevEdge == ABEdge.Bottom ? (int)Math.Round(appbarWindow.ActualHeight) : 0) - 1 + ((tb.Position != TaskBarPosition.Bottom && tb.PreviousPosition == TaskBarPosition.Bottom) ? tb.Height : 0) - ((tb.Position == TaskBarPosition.Bottom && tb.PreviousPosition != TaskBarPosition.Bottom) ? tb.Height : 0); barData.rc.Top = barData.rc.Bottom - (int)Math.Round(appbarWindow.ActualHeight); break; } SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref barData); switch (barData.uEdge) { case (int)ABEdge.Bottom: if (tb.Position == TaskBarPosition.Bottom && tb.PreviousPosition == tb.Position) { barData.rc.Top += (tb.PreviousHeight - tb.Height); barData.rc.Bottom = barData.rc.Top + (int)appbarWindow.ActualHeight; } break; case (int)ABEdge.Top: if (tb.Position == TaskBarPosition.Top && tb.PreviousPosition == tb.Position) { if (tb.PreviousHeight - tb.Height > 0) barData.rc.Top -= (tb.PreviousHeight - tb.Height); barData.rc.Bottom = barData.rc.Top + (int)appbarWindow.ActualHeight; } break; } SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref barData); Rect rect = new Rect((double)barData.rc.Left, (double)barData.rc.Top, (double)(barData.rc.Right - barData.rc.Left), (double)(barData.rc.Bottom - barData.rc.Top)); appbarWindow.Dispatcher.BeginInvoke(new ResizeDelegate(DoResize), DispatcherPriority.ApplicationIdle, appbarWindow, rect); } } } 

Тот же код, который вы можете написать для левого и правого краев. Хорошая работа, Филип Рик, спасибо!

Я модифицировал код от Филиппа Рика (кстати, большое спасибо) за работу в нескольких настройках отображения. Вот мое решение.

 using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.Windows.Threading; namespace AppBarApplication { public enum ABEdge : int { Left = 0, Top, Right, Bottom, None } internal static class AppBarFunctions { [StructLayout(LayoutKind.Sequential)] private struct RECT { public int left; public int top; public int right; public int bottom; } [StructLayout(LayoutKind.Sequential)] private struct APPBARDATA { public int cbSize; public IntPtr hWnd; public int uCallbackMessage; public int uEdge; public RECT rc; public IntPtr lParam; } [StructLayout(LayoutKind.Sequential)] private struct MONITORINFO { public int cbSize; public RECT rcMonitor; public RECT rcWork; public int dwFlags; } private enum ABMsg : int { ABM_NEW = 0, ABM_REMOVE, ABM_QUERYPOS, ABM_SETPOS, ABM_GETSTATE, ABM_GETTASKBARPOS, ABM_ACTIVATE, ABM_GETAUTOHIDEBAR, ABM_SETAUTOHIDEBAR, ABM_WINDOWPOSCHANGED, ABM_SETSTATE } private enum ABNotify : int { ABN_STATECHANGE = 0, ABN_POSCHANGED, ABN_FULLSCREENAPP, ABN_WINDOWARRANGE } [DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)] private static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData); [DllImport("User32.dll", CharSet = CharSet.Auto)] private static extern int RegisterWindowMessage(string msg); [DllImport("User32.dll", CharSet = CharSet.Auto)] private static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); [DllImport("User32.dll", CharSet = CharSet.Auto)] private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO mi); private const int MONITOR_DEFAULTTONEAREST = 0x2; private const int MONITORINFOF_PRIMARY = 0x1; private class RegisterInfo { public int CallbackId { get; set; } public bool IsRegistered { get; set; } public Window Window { get; set; } public ABEdge Edge { get; set; } public WindowStyle OriginalStyle { get; set; } public Point OriginalPosition { get; set; } public Size OriginalSize { get; set; } public ResizeMode OriginalResizeMode { get; set; } public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == CallbackId) { if (wParam.ToInt32() == (int)ABNotify.ABN_POSCHANGED) { ABSetPos(Edge, Window); handled = true; } } return IntPtr.Zero; } } private static Dictionary s_RegisteredWindowInfo = new Dictionary(); private static RegisterInfo GetRegisterInfo(Window appbarWindow) { RegisterInfo reg; if (s_RegisteredWindowInfo.ContainsKey(appbarWindow)) { reg = s_RegisteredWindowInfo[appbarWindow]; } else { reg = new RegisterInfo() { CallbackId = 0, Window = appbarWindow, IsRegistered = false, Edge = ABEdge.Top, OriginalStyle = appbarWindow.WindowStyle, OriginalPosition = new Point(appbarWindow.Left, appbarWindow.Top), OriginalSize = new Size(appbarWindow.ActualWidth, appbarWindow.ActualHeight), OriginalResizeMode = appbarWindow.ResizeMode, }; s_RegisteredWindowInfo.Add(appbarWindow, reg); } return reg; } private static void RestoreWindow(Window appbarWindow) { RegisterInfo info = GetRegisterInfo(appbarWindow); appbarWindow.WindowStyle = info.OriginalStyle; appbarWindow.ResizeMode = info.OriginalResizeMode; appbarWindow.Topmost = false; Rect rect = new Rect(info.OriginalPosition.X, info.OriginalPosition.Y, info.OriginalSize.Width, info.OriginalSize.Height); appbarWindow.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new ResizeDelegate(DoResize), appbarWindow, rect); } public static void SetAppBar(Window appbarWindow, ABEdge edge) { RegisterInfo info = GetRegisterInfo(appbarWindow); info.Edge = edge; APPBARDATA abd = new APPBARDATA(); abd.cbSize = Marshal.SizeOf(abd); abd.hWnd = new WindowInteropHelper(appbarWindow).Handle; if (edge == ABEdge.None) { if (info.IsRegistered) { SHAppBarMessage((int)ABMsg.ABM_REMOVE, ref abd); info.IsRegistered = false; } RestoreWindow(appbarWindow); return; } if (!info.IsRegistered) { info.IsRegistered = true; info.CallbackId = RegisterWindowMessage("AppBarMessage"); abd.uCallbackMessage = info.CallbackId; uint ret = SHAppBarMessage((int)ABMsg.ABM_NEW, ref abd); HwndSource source = HwndSource.FromHwnd(abd.hWnd); source.AddHook(new HwndSourceHook(info.WndProc)); } appbarWindow.WindowStyle = WindowStyle.None; appbarWindow.ResizeMode = ResizeMode.NoResize; appbarWindow.Topmost = true; ABSetPos(info.Edge, appbarWindow); } private delegate void ResizeDelegate(Window appbarWindow, Rect rect); private static void DoResize(Window appbarWindow, Rect rect) { appbarWindow.Width = rect.Width; appbarWindow.Height = rect.Height; appbarWindow.Top = rect.Top; appbarWindow.Left = rect.Left; } private static void GetActualScreenData(ABEdge edge, Window appbarWindow, ref int leftOffset, ref int topOffset, ref int actualScreenWidth, ref int actualScreenHeight) { IntPtr handle = new WindowInteropHelper(appbarWindow).Handle; IntPtr monitorHandle = MonitorFromWindow(handle, MONITOR_DEFAULTTONEAREST); MONITORINFO mi = new MONITORINFO(); mi.cbSize = Marshal.SizeOf(mi); if (GetMonitorInfo(monitorHandle, ref mi)) { if (mi.dwFlags == MONITORINFOF_PRIMARY) { return; } leftOffset = mi.rcWork.left; topOffset = mi.rcWork.top; actualScreenWidth = mi.rcWork.right - leftOffset; actualScreenHeight = mi.rcWork.bottom - mi.rcWork.top; } } private static void ABSetPos(ABEdge edge, Window appbarWindow) { APPBARDATA barData = new APPBARDATA(); barData.cbSize = Marshal.SizeOf(barData); barData.hWnd = new WindowInteropHelper(appbarWindow).Handle; barData.uEdge = (int)edge; int leftOffset = 0; int topOffset = 0; int actualScreenWidth = (int)SystemParameters.PrimaryScreenWidth; int actualScreenHeight = (int)SystemParameters.PrimaryScreenHeight; GetActualScreenData(edge, appbarWindow, ref leftOffset, ref topOffset, ref actualScreenWidth, ref actualScreenHeight); if (barData.uEdge == (int)ABEdge.Left || barData.uEdge == (int)ABEdge.Right) { barData.rc.top = topOffset; barData.rc.bottom = actualScreenHeight; if (barData.uEdge == (int)ABEdge.Left) { barData.rc.left = leftOffset; barData.rc.right = (int)Math.Round(appbarWindow.ActualWidth) + leftOffset; } else { barData.rc.right = actualScreenWidth + leftOffset; barData.rc.left = barData.rc.right - (int)Math.Round(appbarWindow.ActualWidth); } } else { barData.rc.left = leftOffset; barData.rc.right = actualScreenWidth + leftOffset; if (barData.uEdge == (int)ABEdge.Top) { barData.rc.top = topOffset; barData.rc.bottom = (int)Math.Round(appbarWindow.ActualHeight) + topOffset; } else { barData.rc.bottom = actualScreenHeight + topOffset; barData.rc.top = barData.rc.bottom - (int)Math.Round(appbarWindow.ActualHeight); } } SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref barData); SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref barData); Rect rect = new Rect((double)barData.rc.left, (double)barData.rc.top, (double)(barData.rc.right - barData.rc.left), (double)(barData.rc.bottom - barData.rc.top)); //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. appbarWindow.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new ResizeDelegate(DoResize), appbarWindow, rect); } } } 

В 1996 году появилась отличная статья MSDN, которая развлекательно обновляется: Расширьте оболочку Windows 95 с помощью панелей инструментов Desktop Desktop . Следуя его руководству, создается панель приложений на основе WPF, которая обрабатывает ряд сценариев, которые другие ответы на этой странице не делают:

  • Разрешить док в любой части экрана
  • Разрешить док на конкретном мониторе
  • Разрешить изменение размера панели приложений (при желании)
  • Изменения структуры экрана ручного управления и отключения монитора
  • Ручка Win + Shift + Слева и попытка свернуть или переместить окно
  • Управляйте взаимодействием с другими приложениями (OneNote и др.)
  • Ручное масштабирование DPI для каждого монитора

У меня есть демо-приложение и реализация AppBarWindow на GitHub .

Пример использования:

         

Codebehind:

 public partial class MainWindow { public MainWindow() { InitializeComponent(); this.cbEdge.ItemsSource = new[] { AppBarDockMode.Left, AppBarDockMode.Right, AppBarDockMode.Top, AppBarDockMode.Bottom }; this.cbMonitor.ItemsSource = MonitorInfo.GetAllMonitors(); } private void btClose_Click(object sender, RoutedEventArgs e) { Close(); } private void rzThumb_DragCompleted(object sender, DragCompletedEventArgs e) { this.DockedWidthOrHeight += (int)(e.HorizontalChange / VisualTreeHelper.GetDpi(this).PixelsPerDip); } } 

Изменение стыковочного положения:

AppBar состыковался с краями

Изменение размера с помощью большого пальца:

Изменение размера

Сотрудничество с другими приложениями:

координация

Клон из GitHub, если вы хотите его использовать. Сама библиотека представляет собой всего три файла и может быть легко удалена в проекте.

Извините, последний код, который я опубликовал, не работает, когда размер панели задач изменен. Следующее изменение кода работает лучше:

  SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref barData); if (barData.uEdge == (int)ABEdge.Top) barData.rc.bottom = barData.rc.top + (int)Math.Round(appbarWindow.ActualHeight); else if (barData.uEdge == (int)ABEdge.Bottom) barData.rc.top = barData.rc.bottom - (int)Math.Round(appbarWindow.ActualHeight); SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref barData); 

В качестве коммерческой альтернативы см. Готовый к использованию компонент ShellAppBar для WPF, который поддерживает все случаи и secnarios, такие как панель задач, закрепленная на левом, правом, верхнем, нижнем краю, поддержка нескольких мониторов, drag and drop, автогид и т. Д. Это может сэкономить вам время и деньги, пытаясь справиться со всеми этими случаями самостоятельно.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ : Я работаю в LogicNP Software, разработчике ShellAppBar.

Я потратил несколько недель на изучение этой задачи и, наконец, создал очень прочный пакет NuGet, обеспечивающий эту функциональность очень дружелюбно. Просто создайте новое приложение WPF, а затем измените class главного windows из Window to DockWindow (в XAML) и все!

Получите пакет здесь и посмотрите Git repo для демонстрационного приложения.

Interesting Posts

Добавление полей настраиваемого изображения и других полей одновременно

Mac OS X с использованием более 4 ГБ памяти без каких-либо запусков

Как поместить грыбы с annotation_custom () в точные области участка участка?

Как вручную принудительно совершить фиксацию в методе @Transactional?

Как подключить Android-источник к Eclipse

Это приложение изменяет механизм автозапуска из фонового streamа, что может привести к повреждению двигателя и странным сбоям

Должен ли код JQuery идти в верхнем или нижнем колонтитуле?

Invoke или BeginInvoke нельзя вызвать в элементе управления до тех пор, пока дескриптор windows не будет создан

Как автоматически создать каталог на SD-карте

Почему добавление 0,1 несколько раз остается без потерь?

Перемещение файлов PDF в родительскую папку из подпапки с именами переменных

как избежать неопределенного порядка выполнения для конструкторов при использовании std :: make_tuple

Обновление всех сводных таблиц в моей книге Excel с помощью макроса

измените оба названия легенды в ggplot с двумя легендами

Срок службы сеанса symfony2

Давайте будем гением компьютера.