Repository: PhilipRieck/WpfAppBar
Branch: master
Commit: 472bdd5e9257
Files: 14
Total size: 21.7 KB
Directory structure:
gitextract_ex2pgp2f/
├── .gitignore
├── .vs/
│ └── WpfAppBar/
│ └── v16/
│ └── Server/
│ └── sqlite3/
│ └── storage.ide
├── AppBarExample/
│ ├── App.config
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── AppBarExample.csproj
│ ├── MainWindow.xaml
│ └── MainWindow.xaml.cs
├── Readme.md
├── WpfAppBar/
│ ├── AppBarFunctions.cs
│ ├── Interop.cs
│ ├── WpfAppBar.csproj
│ └── WpfAppBar.nuspec
└── WpfAppBar.sln
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
[Bb]in/
[Oo]bj/
*.suo
*.user
*.sln.docstates
_ReSharper*
packages
*.nupkg
================================================
FILE: AppBarExample/App.config
================================================
================================================
FILE: AppBarExample/App.xaml
================================================
================================================
FILE: AppBarExample/App.xaml.cs
================================================
using System.Windows;
namespace AppBarExample
{
///
/// Interaction logic for App.xaml
///
public partial class App : Application
{
}
}
================================================
FILE: AppBarExample/AppBarExample.csproj
================================================
net5.0-windowsWinExetrue1.0.0.0Pilip RieckExample for creating a Windows AppBar with WPFCreative Commons CC0 (https://creativecommons.org/publicdomain/zero/1.0/)s
================================================
FILE: AppBarExample/MainWindow.xaml
================================================
================================================
FILE: AppBarExample/MainWindow.xaml.cs
================================================
using System;
using System.ComponentModel;
using System.Windows;
using WpfAppBar;
namespace AppBarExample
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Normal_OnClick(object sender, RoutedEventArgs e)
{
Normal.IsEnabled = false;
AppBar.IsEnabled = true;
AppBarFunctions.SetAppBar(this, ABEdge.None);
}
private void AppBar_OnClick(object sender, RoutedEventArgs e)
{
AppBar.IsEnabled = false;
Normal.IsEnabled = true;
AppBarFunctions.SetAppBar(this, ABEdge.Left, grid);
}
}
}
================================================
FILE: Readme.md
================================================
WPFAppBar
=========
Available via Nuget : [https://www.nuget.org/packages/WpfAppBar](https://www.nuget.org/packages/WpfAppBar)
As seen in this StackOverflow question:
[How do you do AppBar docking (to screen edge, like WinAmp) in WPF?](http://stackoverflow.com/q/75785/12643)
Looking for a WinForms version:
https://github.com/tip2tail/t2tWinFormAppBarLib
What is it?
----------
A helper for turning a WPF window into an "AppBar" like the Windows taskbar.
I hope you're not writing any applications that need to do this, but if you
are, hopefully this library will help.
How do I use it?
----------------
To use, just call this code from anywhere within a normal WPF window (say a button click or the initialize). Note that you can not call this until AFTER the window is initialized, if the HWND hasn't been created yet (like in the constructor), an error will occur.
```C#
//Make the window an appbar:
AppBarFunctions.SetAppBar(this, ABEdge.Right);
// If you want to resize the window by its content:
AppBarFunctions.SetAppBar(this, ABEdge.Right, grid);
AppBarFunctions.SetAppBar(this, ABEdge.Right, wrapPanel);
// etc...
//Restore the window to a normal window:
AppBarFunctions.SetAppBar(this, ABEdge.None);
```
I found a bug!
--------------
Please add an issue, or better yet send a pull request.
Thanks!
That sounds okay... but licensing?
----------------------------------
No warranty of any kind implied.
Creative Commons CC0 (https://creativecommons.org/publicdomain/zero/1.0/)
================================================
FILE: WpfAppBar/AppBarFunctions.cs
================================================
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Threading;
namespace WpfAppBar
{
public enum ABEdge : int
{
Left = 0,
Top,
Right,
Bottom,
None
}
public static class AppBarFunctions
{
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 bool OriginalTopmost { get; set; }
public FrameworkElement ChildElement { get; set; }
public Rect? DockedSize { get; set; }
public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam,
IntPtr lParam, ref bool handled)
{
if (msg == CallbackId)
{
if (wParam.ToInt32() == (int)Interop.ABNotify.ABN_POSCHANGED)
{
ABSetPos(this, Window, ChildElement);
handled = true;
}
}
return IntPtr.Zero;
}
}
private static readonly Dictionary RegisteredWindowInfo
= new Dictionary();
private static RegisterInfo GetRegisterInfo(Window appbarWindow)
{
RegisterInfo reg;
if (RegisteredWindowInfo.ContainsKey(appbarWindow))
{
reg = 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,
OriginalTopmost = appbarWindow.Topmost,
DockedSize = null
};
RegisteredWindowInfo.Add(appbarWindow, reg);
}
return reg;
}
private static void RestoreWindow(Window appbarWindow)
{
var info = GetRegisterInfo(appbarWindow);
appbarWindow.WindowStyle = info.OriginalStyle;
appbarWindow.ResizeMode = info.OriginalResizeMode;
appbarWindow.Topmost = info.OriginalTopmost;
info.DockedSize = null;
var 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, FrameworkElement childElement = null, bool topMost = true)
{
var info = GetRegisterInfo(appbarWindow);
info.Edge = edge;
info.ChildElement = childElement;
var abd = new Interop.APPBARDATA();
abd.cbSize = Marshal.SizeOf(abd);
abd.hWnd = new WindowInteropHelper(appbarWindow).Handle;
int renderPolicy;
if (edge == ABEdge.None)
{
if (info.IsRegistered)
{
Interop.SHAppBarMessage((int)Interop.ABMsg.ABM_REMOVE, ref abd);
info.IsRegistered = false;
}
RestoreWindow(appbarWindow);
// Restore normal desktop window manager attributes
renderPolicy = (int)Interop.DWMNCRenderingPolicy.UseWindowStyle;
Interop.DwmSetWindowAttribute(abd.hWnd, (int)Interop.DWMWINDOWATTRIBUTE.DWMA_EXCLUDED_FROM_PEEK, ref renderPolicy, sizeof(int));
Interop.DwmSetWindowAttribute(abd.hWnd, (int)Interop.DWMWINDOWATTRIBUTE.DWMA_DISALLOW_PEEK, ref renderPolicy, sizeof(int));
return;
}
if (!info.IsRegistered)
{
info.IsRegistered = true;
info.CallbackId = Interop.RegisterWindowMessage("AppBarMessage");
abd.uCallbackMessage = info.CallbackId;
var ret = Interop.SHAppBarMessage((int)Interop.ABMsg.ABM_NEW, ref abd);
var source = HwndSource.FromHwnd(abd.hWnd);
source.AddHook(info.WndProc);
}
appbarWindow.WindowStyle = WindowStyle.None;
appbarWindow.ResizeMode = ResizeMode.NoResize;
appbarWindow.Topmost = topMost;
// Set desktop window manager attributes to prevent window
// from being hidden when peeking at the desktop or when
// the 'show desktop' button is pressed
renderPolicy = (int)Interop.DWMNCRenderingPolicy.Enabled;
Interop.DwmSetWindowAttribute(abd.hWnd, (int)Interop.DWMWINDOWATTRIBUTE.DWMA_EXCLUDED_FROM_PEEK, ref renderPolicy, sizeof(int));
Interop.DwmSetWindowAttribute(abd.hWnd, (int)Interop.DWMWINDOWATTRIBUTE.DWMA_DISALLOW_PEEK, ref renderPolicy, sizeof(int));
ABSetPos(info, appbarWindow, childElement);
}
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(RegisterInfo info, Window appbarWindow, FrameworkElement childElement)
{
var edge = info.Edge;
var barData = new Interop.APPBARDATA();
barData.cbSize = Marshal.SizeOf(barData);
barData.hWnd = new WindowInteropHelper(appbarWindow).Handle;
barData.uEdge = (int)edge;
// Transforms a coordinate from WPF space to Screen space
var toPixel = PresentationSource.FromVisual(appbarWindow).CompositionTarget.TransformToDevice;
// Transforms a coordinate from Screen space to WPF space
var toWpfUnit = PresentationSource.FromVisual(appbarWindow).CompositionTarget.TransformFromDevice;
// Transform window size from wpf units (1/96 ") to real pixels, for win32 usage
var sizeInPixels = (childElement != null ?
toPixel.Transform(new Vector(childElement.ActualWidth, childElement.ActualHeight)) :
toPixel.Transform(new Vector(appbarWindow.ActualWidth, appbarWindow.ActualHeight)));
// Even if the documentation says SystemParameters.PrimaryScreen{Width, Height} return values in
// "pixels", they return wpf units instead.
var actualWorkArea = GetActualWorkArea(info);
var screenSizeInPixels =
toPixel.Transform(new Vector(actualWorkArea.Width, actualWorkArea.Height));
var workTopLeftInPixels =
toPixel.Transform(new Point(actualWorkArea.Left, actualWorkArea.Top));
var workAreaInPixelsF = new Rect(workTopLeftInPixels, screenSizeInPixels);
if (barData.uEdge == (int)ABEdge.Left || barData.uEdge == (int)ABEdge.Right)
{
barData.rc.top = (int)workAreaInPixelsF.Top;
barData.rc.bottom = (int)workAreaInPixelsF.Bottom;
if (barData.uEdge == (int)ABEdge.Left)
{
barData.rc.left = (int)workAreaInPixelsF.Left;
//Left might not always be zero so we need to accommodate for that.
//For example, if the Start Menu is docked LEFT, if we don't do the math, we'll end up with a negative size error
barData.rc.right = barData.rc.left + (int)Math.Round(sizeInPixels.X);
}
else {
barData.rc.right = (int)workAreaInPixelsF.Right;
barData.rc.left = barData.rc.right - (int)Math.Round(sizeInPixels.X);
}
}
else
{
barData.rc.left = (int)workAreaInPixelsF.Left;
barData.rc.right = (int)workAreaInPixelsF.Right;
if (barData.uEdge == (int)ABEdge.Top)
{
barData.rc.top = (int)workAreaInPixelsF.Top;
//Top might not always be zero so we need to accommodate for that.
//For example, if the Start Menu is docked TOP, if we don't do the math, we'll end up with a negative size error
barData.rc.bottom = barData.rc.top + (int)Math.Round(sizeInPixels.Y);
}
else {
barData.rc.bottom = (int)workAreaInPixelsF.Bottom;
barData.rc.top = barData.rc.bottom - (int)Math.Round(sizeInPixels.Y);
}
}
Interop.SHAppBarMessage((int)Interop.ABMsg.ABM_QUERYPOS, ref barData);
Interop.SHAppBarMessage((int)Interop.ABMsg.ABM_SETPOS, ref barData);
// transform back to wpf units, for wpf window resizing in DoResize.
var location = toWpfUnit.Transform(new Point(barData.rc.left, barData.rc.top));
var dimension = toWpfUnit.Transform(new Vector(
(barData.rc.right - barData.rc.left),
(barData.rc.bottom - barData.rc.top)));
var rect = new Rect(location, new Size(dimension.X, dimension.Y));
info.DockedSize = rect;
//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);
}
private static Rect GetActualWorkArea(RegisterInfo info)
{
var hWnd = new WindowInteropHelper(info.Window).Handle;
var cwa = GetMonitorWorkArea(Interop.MonitorFromWindow(hWnd, Interop.MonitorDefaultTo.MONITOR_DEFAULTTONEAREST));
var wa = new Rect(new Point(cwa.left, cwa.top), new Point(cwa.right, cwa.bottom));
if (info.DockedSize != null)
{
wa.Union(info.DockedSize.Value);
}
return wa;
}
private static Interop.RECT GetMonitorWorkArea(IntPtr hMonitor)
{
var monitorInfo = new Interop.MONITORINFO();
monitorInfo.cbSize = Marshal.SizeOf(monitorInfo);
Interop.GetMonitorInfo(hMonitor, ref monitorInfo);
return monitorInfo.rcWork;
}
}
}
================================================
FILE: WpfAppBar/Interop.cs
================================================
using System;
using System.Runtime.InteropServices;
namespace WpfAppBar
{
class Interop
{
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential)]
internal struct APPBARDATA
{
public int cbSize;
public IntPtr hWnd;
public int uCallbackMessage;
public int uEdge;
public RECT rc;
public IntPtr lParam;
}
[System.Flags]
internal enum DWMWINDOWATTRIBUTE
{
DWMA_NCRENDERING_ENABLED = 1,
DWMA_NCRENDERING_POLICY,
DWMA_TRANSITIONS_FORCEDISABLED,
DWMA_ALLOW_NCPAINT,
DWMA_CPATION_BUTTON_BOUNDS,
DWMA_NONCLIENT_RTL_LAYOUT,
DWMA_FORCE_ICONIC_REPRESENTATION,
DWMA_FLIP3D_POLICY,
DWMA_EXTENDED_FRAME_BOUNDS,
DWMA_HAS_ICONIC_BITMAP,
DWMA_DISALLOW_PEEK,
DWMA_EXCLUDED_FROM_PEEK,
DWMA_LAST
}
[System.Flags]
internal enum DWMNCRenderingPolicy
{
UseWindowStyle,
Disabled,
Enabled,
Last
}
internal 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
}
internal enum ABNotify : int
{
ABN_STATECHANGE = 0,
ABN_POSCHANGED,
ABN_FULLSCREENAPP,
ABN_WINDOWARRANGE
}
internal enum MonitorDefaultTo
{
MONITOR_DEFAULTTONULL,
MONITOR_DEFAULTTOPRIMARY,
MONITOR_DEFAULTTONEAREST
}
[StructLayout(LayoutKind.Sequential)]
internal struct MONITORINFO
{
public int cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
}
[DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)]
internal static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
internal static extern int RegisterWindowMessage(string msg);
[DllImport("dwmapi.dll")]
internal static extern int DwmSetWindowAttribute(IntPtr hWnd, int attr, ref int attrValue, int attrSize);
[DllImport("User32.dll")]
internal static extern IntPtr MonitorFromWindow(IntPtr hWnd, MonitorDefaultTo dwFlags);
[DllImport("User32.dll")]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
}
}
================================================
FILE: WpfAppBar/WpfAppBar.csproj
================================================
netcoreapp3.1;net45;net5.0-windowsLibrarytrue3.0.0.0Pilip RieckUtilities for creating a Windows AppBar with WPFCreative Commons CC0 (https://creativecommons.org/publicdomain/zero/1.0/)s
================================================
FILE: WpfAppBar/WpfAppBar.nuspec
================================================
$id$$version$$title$$author$$author$https://github.com/PhilipRieck/WpfAppBarfalse$description$Add support for .net core 3 (via StummeJ)Creative Commons CC0 ( https://creativecommons.org/publicdomain/zero/1.0/ )WPF AppBar
================================================
FILE: WpfAppBar.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30110.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfAppBar", "WpfAppBar\WpfAppBar.csproj", "{86F999C7-4543-41DE-8E6D-9AB41AC0FF8E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppBarExample", "AppBarExample\AppBarExample.csproj", "{6FA45981-2F56-4B8A-911F-DC515FB0D980}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{86F999C7-4543-41DE-8E6D-9AB41AC0FF8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86F999C7-4543-41DE-8E6D-9AB41AC0FF8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{86F999C7-4543-41DE-8E6D-9AB41AC0FF8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86F999C7-4543-41DE-8E6D-9AB41AC0FF8E}.Release|Any CPU.Build.0 = Release|Any CPU
{6FA45981-2F56-4B8A-911F-DC515FB0D980}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FA45981-2F56-4B8A-911F-DC515FB0D980}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FA45981-2F56-4B8A-911F-DC515FB0D980}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FA45981-2F56-4B8A-911F-DC515FB0D980}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal