在WPF中是否有关于AppBar对接(例如锁定到屏幕边缘)的完整指南?我知道需要进行InterOp调用,但我正在寻找基于简单WPF表单的概念证明,或者可以使用的组件化版本。相关资源:
kiz8lqtg1#
**请注意:这个问题收集了大量的反馈,下面的一些人提出了很好的观点或修正。因此,虽然我将保留这里的代码(并可能更新它),但我还创建了一个WpfAppBar project on github。请随意发送pull requests。
该项目还将构建为WpfAppBar nuget package我从问题中提供的第一个链接(http://www.codeproject.com/KB/dotnet/AppBar.aspx)中获取代码,并对其进行修改以做两件事:1.与WPF合作1.“独立”--如果你把这个文件放在你的项目中,你可以调用AppBarFunctions.SetAppBar(...)而不需要对窗口做任何修改。这种方法不创建基类。要使用它,只需在一个普通的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<Window, RegisterInfo> s_RegisteredWindowInfo = new Dictionary<Window, RegisterInfo>(); 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); } } }
iq3niunx2#
有一篇1996年的优秀MSDN文章,它是有趣的最新文章:Extend the Windows 95 Shell with Application Desktop Toolbars。遵循它的指导会产生一个基于WPF的应用栏,它可以处理本页上其他答案所没有的许多场景:
我有一个demo app and the implementation of AppBarWindow on GitHub和一个Nuget module。示例用途:
AppBarWindow
<apb:AppBarWindow x:Class="WpfAppBarDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:apb="clr-namespace:WpfAppBar;assembly=WpfAppBar" DataContext="{Binding RelativeSource={RelativeSource Self}}" Title="MainWindow" DockedWidthOrHeight="200" MinHeight="100" MinWidth="100"> <Grid> <Button x:Name="btClose" Content="Close" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Height="23" Margin="10,10,0,0" Click="btClose_Click"/> <ComboBox x:Name="cbMonitor" SelectedItem="{Binding Path=Monitor, Mode=TwoWay}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Margin="10,38,0,0"/> <ComboBox x:Name="cbEdge" SelectedItem="{Binding Path=DockMode, Mode=TwoWay}" HorizontalAlignment="Left" Margin="10,65,0,0" VerticalAlignment="Top" Width="120"/> <Thumb Width="5" HorizontalAlignment="Right" Background="Gray" x:Name="rzThumb" Cursor="SizeWE" DragCompleted="rzThumb_DragCompleted" /> </Grid> </apb:AppBarWindow>
代码隐藏:
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的合作:
克隆from GitHub如果你想使用它。库本身只有三个文件,可以很容易地放在项目中。
35g0bw713#
很高兴找到了这个问题。上面的类确实很有用,但并没有完全涵盖AppBar实现的所有基础。要完全实现AppBar的所有行为(科普全屏应用程序等),您也需要阅读这篇MSDN文章。http://msdn.microsoft.com/en-us/library/bb776821.aspx
798qvoo84#
对不起,我的英语…这是菲利普·里克的解答,并作了一些修正。它可以正确处理任务栏位置和大小的变化。
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<Window, RegisterInfo> s_RegisteredWindowInfo = new Dictionary<Window, RegisterInfo>(); 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); } } }
同样的代码,你可以写的左和右边缘。干得好,菲利普·里克,谢谢!
alen0pnh5#
我修改了Philip Rieck的代码(顺便说一句。非常感谢)在多个显示设置中工作。这是我的解决方案。
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<Window, RegisterInfo> s_RegisteredWindowInfo = new Dictionary<Window, RegisterInfo>(); 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); } } }
jogvjijk6#
作为一个商业替代方案,请参阅WPF的现成ShellAppBar组件,它支持所有情况和secnarios,如任务栏停靠到左,右,顶部,底部边缘,支持多个显示器,拖动停靠,自动隐藏等。它可以保存您的时间和金钱比试图处理所有这些案件自己。
免责声明:我在LogicNP Software工作,它是ShellAppBar的开发者。
mw3dktmi7#
对不起,我发布的最后一个代码在调整任务栏大小时不起作用。下面的代码更改似乎更好地工作:
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);
flseospp8#
我花了几个星期的时间来探索这个挑战,最后创建了一个非常可靠的NuGet包,以非常友好的方式提供了这个功能。只需创建一个新的WPF应用程序,然后将主窗口的类从Window更改为DockWindow(在XAML中),就可以了!获取here包并查看Git repo以获取演示应用程序。
8条答案
按热度按时间kiz8lqtg1#
**请注意:这个问题收集了大量的反馈,下面的一些人提出了很好的观点或修正。因此,虽然我将保留这里的代码(并可能更新它),但我还创建了一个WpfAppBar project on github。请随意发送pull requests。
该项目还将构建为WpfAppBar nuget package
我从问题中提供的第一个链接(http://www.codeproject.com/KB/dotnet/AppBar.aspx)中获取代码,并对其进行修改以做两件事:
1.与WPF合作
1.“独立”--如果你把这个文件放在你的项目中,你可以调用AppBarFunctions.SetAppBar(...)而不需要对窗口做任何修改。
这种方法不创建基类。
要使用它,只需在一个普通的wpf窗口中的任何地方调用这段代码(比如单击按钮或初始化)。注意,在窗口初始化之前,你不能调用这个函数,如果HWND还没有被创建(就像在构造函数中一样),就会发生错误。
将窗口设置为应用栏:
将窗口还原为普通窗口:
下面是该文件的完整代码-注意您需要将第7行的名称空间更改为适当的名称空间。
iq3niunx2#
有一篇1996年的优秀MSDN文章,它是有趣的最新文章:Extend the Windows 95 Shell with Application Desktop Toolbars。遵循它的指导会产生一个基于WPF的应用栏,它可以处理本页上其他答案所没有的许多场景:
我有一个demo app and the implementation of
AppBarWindow
on GitHub和一个Nuget module。示例用途:
代码隐藏:
更改停靠位置:
用拇指调整大小:
与其他appbar的合作:
克隆from GitHub如果你想使用它。库本身只有三个文件,可以很容易地放在项目中。
35g0bw713#
很高兴找到了这个问题。上面的类确实很有用,但并没有完全涵盖AppBar实现的所有基础。
要完全实现AppBar的所有行为(科普全屏应用程序等),您也需要阅读这篇MSDN文章。
http://msdn.microsoft.com/en-us/library/bb776821.aspx
798qvoo84#
对不起,我的英语…这是菲利普·里克的解答,并作了一些修正。它可以正确处理任务栏位置和大小的变化。
同样的代码,你可以写的左和右边缘。干得好,菲利普·里克,谢谢!
alen0pnh5#
我修改了Philip Rieck的代码(顺便说一句。非常感谢)在多个显示设置中工作。这是我的解决方案。
jogvjijk6#
作为一个商业替代方案,请参阅WPF的现成ShellAppBar组件,它支持所有情况和secnarios,如任务栏停靠到左,右,顶部,底部边缘,支持多个显示器,拖动停靠,自动隐藏等。它可以保存您的时间和金钱比试图处理所有这些案件自己。
免责声明:我在LogicNP Software工作,它是ShellAppBar的开发者。
mw3dktmi7#
对不起,我发布的最后一个代码在调整任务栏大小时不起作用。下面的代码更改似乎更好地工作:
flseospp8#
我花了几个星期的时间来探索这个挑战,最后创建了一个非常可靠的NuGet包,以非常友好的方式提供了这个功能。只需创建一个新的WPF应用程序,然后将主窗口的类从Window更改为DockWindow(在XAML中),就可以了!
获取here包并查看Git repo以获取演示应用程序。