AppBar可与具有不同DPI的多个屏幕一起使用吗?

时间:2019-01-22 13:14:02

标签: vb.net appbar

我需要将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问题的机构吗?

谢谢

0 个答案:

没有答案