我需要将WPF表单停靠在桌面顶部(应用栏),但是到目前为止,我所看到的所有示例都没有考虑多个监视器和多个DPI。
到目前为止,这是我的代码。
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Interop
Imports Microsoft.Win32
Public Class MyAppBar
Inherits Window
Private Class ScreenInfo
Public Property Bounds As System.Drawing.Rectangle
Public Property Factor As Decimal
End Class
Private _screenFactors As New Dictionary(Of Forms.Screen, Decimal)
Private _isReady As Boolean = False
Private _screens As New List(Of Forms.Screen)
Private _screen As Forms.Screen
Private _screenIndex As Integer = 0
Public Property ScreenIndex As Integer
Get
Return _screenIndex
End Get
Set(value As Integer)
If value = _screenIndex Then
Exit Property
End If
_screenIndex = value
If _isReady Then
_screen = _screens(value)
Call Rebuild()
End If
End Set
End Property
Private Sub AppBarForm_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Me.ResizeMode = ResizeMode.NoResize
Me.ShowInTaskbar = False
Me.Topmost = True
Me.WindowStyle = WindowStyle.None
Me.Height = 50
_isReady = True
Call InitScreens()
Call ToggleAppBar()
End Sub
Private Sub AppBarForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
Call ToggleAppBar()
End Sub
Public Sub Debug(text As String)
Dim i As Integer = 1
For Each scr As Forms.Screen In _screens
App.LogsDebug.Add($"Screen: {i}, Width: {scr.Bounds.Width}, Height: {scr.Bounds.Height}, Left: {scr.Bounds.Left}, Right: {scr.Bounds.Right}, Factor: {_screenFactors(scr)}")
i += 1
Next
End Sub
Private Sub InitScreens()
_screens.Clear()
_screenFactors.Clear()
_screens.AddRange((From mm In Forms.Screen.AllScreens Select mm Order By mm.Bounds.Left).ToArray)
If _screens.Count = 1 Then
Dim source As PresentationSource = PresentationSource.FromVisual(Me)
_screenFactors.Add(_screens(0), source.CompositionTarget.TransformToDevice.M11)
Else
For Each scr In _screens
Dim pixelX As Integer
Dim pixelY As Integer
scr.GetDpi(DpiType.Effective, pixelX, pixelY)
Dim factor As Decimal = 96 / pixelX
_screenFactors.Add(scr, factor)
Next
End If
If _screenIndex > _screens.Count - 1 Then _screenIndex = _screens.Count - 1
_screen = _screens(_screenIndex)
End Sub
Private ReadOnly Property Handle As IntPtr
Get
Static windowHelper As New WindowInteropHelper(Me)
Return windowHelper.Handle
End Get
End Property
<StructLayout(LayoutKind.Sequential)> Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
End Structure
<StructLayout(LayoutKind.Sequential)> Structure APPBARDATA
Public cbSize As Integer
Public hWnd As IntPtr
Public uCallbackMessage As Integer
Public uEdge As Integer
Public rc As RECT
Public lParam As IntPtr
End Structure
Enum ABMsg
ABM_NEW = 0
ABM_REMOVE = 1
ABM_QUERYPOS = 2
ABM_SETPOS = 3
End Enum
Private fBarRegistered As Boolean = False
<DllImport("SHELL32", CallingConvention:=CallingConvention.StdCall)>
Public Shared Function SHAppBarMessage(ByVal dwMessage As Integer, ByRef BarrData As APPBARDATA) As Integer
End Function
<DllImport("USER32")>
Public Shared Function GetSystemmetric(ByVal Index As Integer) As Integer
End Function
<DllImport("User32.dll", ExactSpelling:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)>
Public Shared Function MoveWindow(ByVal hWnd As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal cX As Integer, ByVal cY As Integer, ByVal repaint As Boolean) As Boolean
End Function
<DllImport("User32.dll", CharSet:=CharSet.Auto)>
Public Shared Function RegisterWindowMessage(ByVal msg As String) As Integer
End Function
Private uCallBack As Integer
Private Sub ToggleAppBar()
Dim windowHelper As New WindowInteropHelper(Me)
Dim abd As New APPBARDATA
Dim ret As Integer
abd.cbSize = Marshal.SizeOf(abd)
abd.hWnd = Me.Handle
If Not fBarRegistered Then
uCallBack = RegisterWindowMessage("AppBarMessage")
abd.uCallbackMessage = uCallBack
ret = SHAppBarMessage(ABMsg.ABM_NEW, abd)
fBarRegistered = True
Rebuild()
Else
ret = SHAppBarMessage(ABMsg.ABM_REMOVE, abd)
fBarRegistered = False
End If
End Sub
Public Sub Rebuild()
If Not _isReady Then Exit Sub
Dim b As New System.Drawing.Rectangle(_screen.Bounds.Left, 0, _screen.Bounds.Width, Me.Height)
Dim abd As New APPBARDATA
abd.cbSize = Marshal.SizeOf(abd)
abd.hWnd = Me.Handle
abd.uEdge = 1 ' Top
abd.rc.left = b.Left
abd.rc.right = b.Right
abd.rc.top = b.Top
abd.rc.bottom = b.Bottom
SHAppBarMessage(ABMsg.ABM_QUERYPOS, abd)
SHAppBarMessage(ABMsg.ABM_SETPOS, abd)
MoveWindow(abd.hWnd, b.Left, b.Top, b.Width, b.Height, True)
MyBase.Left = b.Left
MyBase.Width = b.Width
MyBase.Top = b.Top
MyBase.Height = b.Height
End Sub
End Class
解决了多个监视器和DPI问题的机构吗?
谢谢