61

WPF で AppBar ドッキング (画面端へのロックなど) を行うための完全なガイダンスはありますか? InterOp 呼び出しを行う必要があることは理解していますが、単純な WPF フォームに基づく概念実証、または使用できるコンポーネント化されたバージョンのいずれかを探しています。

関連リソース:

4

8 に答える 8

89

注意してください:この質問はかなりの量のフィードバックを集めました. したがって、ここにコードを残しておきます (場合によっては更新します) が、github で WpfAppBar プロジェクトも作成しました。気軽にプルリクエストを送ってください。

同じプロジェクトがWpfAppBar nuget パッケージにもビルドされます


質問で提供された最初のリンク ( http://www.codeproject.com/KB/dotnet/AppBar.aspx ) からコードを取得し、次の 2 つのことを行うように変更しました。

  1. WPF を操作する
  2. 「スタンドアロン」にする - この単一のファイルをプロジェクトに配置すると、ウィンドウをさらに変更することなく 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);
        }
    }
}
于 2008-09-17T16:23:06.967 に答える
4

私の英語でごめんなさい...これがPhilipRieckの解決策です。タスクバーの位置とサイズの変更で正しく機能します。

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);
        }
    }
}

左端と右端に記述できるのと同じコード。よくやった、フィリップ・リーク、ありがとう!

于 2011-04-10T06:39:13.887 に答える
4

複数のディスプレイ設定で動作するように、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);
        }
    }
}
于 2013-09-19T13:53:31.957 に答える
3

この質問を見つけてとてもうれしいです。上記のクラスは本当に便利ですが、AppBar実装のすべての基本を完全に網羅しているわけではありません。

AppBarのすべての動作(フルスクリーンアプリなどに対応)を完全に実装するには、このMSDNの記事も読む必要があります。

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

于 2009-03-08T20:34:13.403 に答える
1

タスクバーのサイズを変更すると、最後に投稿したコードが機能しませんでした。次のコード変更は、よりうまく機能するようです。

  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);
于 2009-04-22T20:50:19.757 に答える
1

私は数週間かけてこの課題を調査し、最終的に、この機能を非常に使いやすい方法で提供する非常に堅実な NuGet パッケージを作成しました。新しい WPF アプリを作成し、メイン ウィンドウのクラスを (XAML で) Window から DockWindow に変更するだけです。

こちらからパッケージを取得し、デモ アプリの Git リポジトリを参照してください。

于 2015-10-22T02:16:20.700 に答える