Files
EgtWPFLib5/EgtMainWindow.vb
T
Dario Sassi 00a338c202 Revert "Merge commit 'f1aae48a2b80f96ae94b59a69addd6cc6e48ee14'"
This reverts commit 1f49d0936e, reversing
changes made to 236eeac038.
2025-03-21 19:21:02 +01:00

576 lines
20 KiB
VB.net

' Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
'
' Step 1a) Using this custom control in a XAML file that exists in the current project.
' Add this XmlNamespace attribute to the root element of the markup file where it is
' to be used:
'
' xmlns:MyNamespace="clr-namespace:EgtWPFLib5"
'
'
' Step 1b) Using this custom control in a XAML file that exists in a different project.
' Add this XmlNamespace attribute to the root element of the markup file where it is
' to be used:
'
' xmlns:MyNamespace="clr-namespace:EgtWPFLib5;assembly=EgtWPFLib5"
'
' You will also need to add a project reference from the project where the XAML file lives
' to this project and Rebuild to avoid compilation errors:
'
' Right click on the target project in the Solution Explorer and
' "Add Reference"->"Projects"->[Browse to and select this project]
'
'
' Step 2)
' Go ahead and use your control in the XAML file. Note that Intellisense in the
' XML editor does not currently work on custom controls and its child elements.
'
' <MyNamespace:EgtMainWindow/>
'
Imports System.Runtime.InteropServices
Imports System.Windows.Controls.Primitives
Imports System.Windows.Interop
<TemplatePart(Name:="PART_MoveRectangle", Type:=GetType(TextBlock))>
<TemplatePart(Name:="PART_ResizeGrid", Type:=GetType(Grid))>
<TemplatePart(Name:="PART_TitleBarIcon", Type:=GetType(Image))>
Public Class EgtMainWindow
Inherits System.Windows.Window
<DllImport("User32")>
Friend Shared Function GetCursorPos(ByRef pt As Win32Point) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<StructLayout(LayoutKind.Sequential)>
Friend Structure Win32Point
Public X As Int32
Public Y As Int32
End Structure
Private m_bFirst As Boolean = False
Private _hwndSource As HwndSource
Private m_MoveRectangle As TextBlock
Private m_MinimizeButton As Button
Private m_MaximizeButton As Button
Private m_RestoreButton As Button
Private m_CloseButton As Button
' Proprietà che permette di impostare l'altezza della TitleBar
Public Shared ReadOnly CloseCommandProperty As DependencyProperty = DependencyProperty.Register("CloseCommand", GetType(ICommand), GetType(EgtMainWindow), New PropertyMetadata(Nothing))
Public Property CloseCommand() As ICommand
Get
Return DirectCast(GetValue(CloseCommandProperty), ICommand)
End Get
Set(ByVal value As ICommand)
SetValue(CloseCommandProperty, value)
End Set
End Property
' Proprietà che permette di impostare la Window lanciata sul click dell'icona della TitleBar
Public Shared ReadOnly AboutBoxCommandProperty As DependencyProperty = DependencyProperty.Register("AboutBoxCommand", GetType(ICommand), GetType(EgtMainWindow), New PropertyMetadata(Nothing))
Public Property AboutBoxCommand() As ICommand
Get
Return DirectCast(GetValue(AboutBoxCommandProperty), ICommand)
End Get
Set(ByVal value As ICommand)
SetValue(AboutBoxCommandProperty, value)
End Set
End Property
' Proprietà che permette di impostare uno UserControl per aggiungere elementi alla TitleBar
Public Shared ReadOnly TitlePanelProperty As DependencyProperty = DependencyProperty.Register("TitlePanel", GetType(Panel), GetType(EgtMainWindow), New PropertyMetadata(Nothing))
Public Property TitlePanel() As Panel
Get
Return DirectCast(GetValue(TitlePanelProperty), Panel)
End Get
Set(ByVal value As Panel)
SetValue(TitlePanelProperty, value)
End Set
End Property
' Proprietà che permette di impostare il nome del progetto
Public Shared ReadOnly ProjectNameProperty As DependencyProperty = DependencyProperty.Register("ProjectName", GetType(String), GetType(EgtMainWindow), New PropertyMetadata(""))
Public Property ProjectName() As Double
Get
Return CType(GetValue(ProjectNameProperty), Double)
End Get
Set(ByVal value As Double)
SetValue(ProjectNameProperty, value)
End Set
End Property
' Proprietà che permette di impostare la path del progetto
Public Shared ReadOnly ProjectPathProperty As DependencyProperty = DependencyProperty.Register("ProjectPath", GetType(String), GetType(EgtMainWindow), New PropertyMetadata(""))
Public Property ProjectPath() As Double
Get
Return CType(GetValue(ProjectPathProperty), Double)
End Get
Set(ByVal value As Double)
SetValue(ProjectPathProperty, value)
End Set
End Property
Shared Sub New()
'This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
'This style is defined in themes\generic.xaml
DefaultStyleKeyProperty.OverrideMetadata(GetType(EgtMainWindow), New FrameworkPropertyMetadata(GetType(EgtMainWindow)))
End Sub
Sub New()
' necessario per impostare l'altezza della barra che per default si autoadatta al contenuto
'TitleBarHeight = Double.NaN
End Sub
Sub New(Owner As Window)
Me.Owner = Owner
End Sub
Public Overrides Sub OnApplyTemplate()
MyBase.OnApplyTemplate()
' Retrieve the Button from the current template
m_MoveRectangle = TryCast(MyBase.GetTemplateChild("PART_MoveRectangle"), TextBlock)
' Retrive the resizeRectangle from the current template
Dim resizeGrid As Grid = TryCast(GetTemplateChild("PART_ResizeGrid"), Grid)
If resizeGrid IsNot Nothing Then
For Each element As UIElement In resizeGrid.Children
Dim resizeRectangle As Rectangle = TryCast(element, Rectangle)
If resizeRectangle IsNot Nothing Then
AddHandler resizeRectangle.PreviewMouseDown, AddressOf ResizeRectangle_PreviewMouseDown
AddHandler resizeRectangle.MouseMove, AddressOf ResizeRectangle_MouseMove
End If
Next
End If
Dim TitleBarIcon As Image = TryCast(MyBase.GetTemplateChild("PART_TitleBarIcon"), Image)
' Hook up the event handler
If m_MoveRectangle IsNot Nothing Then
AddHandler m_MoveRectangle.MouseLeftButtonDown, AddressOf MoveRectangle_MouseLeftButtonDown
AddHandler m_MoveRectangle.MouseLeftButtonUp, AddressOf MoveRectangle_MouseLeftButtonUp
AddHandler m_MoveRectangle.MouseMove, AddressOf MoveRectangle_MouseMove
End If
m_MinimizeButton = TryCast(GetTemplateChild("MinimizeButton"), Button)
If m_MinimizeButton IsNot Nothing Then
AddHandler m_MinimizeButton.Click, AddressOf MinimizeClick
End If
m_MaximizeButton = TryCast(GetTemplateChild("MaximizeButton"), Button)
If m_MaximizeButton IsNot Nothing Then
AddHandler m_MaximizeButton.Click, AddressOf MaximizeClick
End If
m_RestoreButton = TryCast(GetTemplateChild("RestoreButton"), Button)
If m_RestoreButton IsNot Nothing Then
AddHandler m_RestoreButton.Click, AddressOf RestoreClick
End If
Dim closeButton As Button = TryCast(GetTemplateChild("CloseButton"), Button)
If closeButton IsNot Nothing Then
AddHandler closeButton.Click, AddressOf CloseClick
End If
End Sub
Private Sub EgtMainWindow_StateChanged(sender As Object, e As EventArgs) Handles Me.StateChanged
If WindowState = Windows.WindowState.Maximized Then
If Not IsNothing(m_RestoreButton) AndAlso Not IsNothing(m_MaximizeButton) Then
m_RestoreButton.Visibility = Visibility.Visible
m_MaximizeButton.Visibility = Visibility.Collapsed
End If
Else
If Not IsNothing(m_RestoreButton) AndAlso Not IsNothing(m_MaximizeButton) Then
m_RestoreButton.Visibility = Visibility.Collapsed
m_MaximizeButton.Visibility = Visibility.Visible
End If
End If
End Sub
Private Sub EgtMainWindow_SourceInitialized(sender As Object, e As EventArgs) Handles Me.SourceInitialized
Dim handle As System.IntPtr = (New WindowInteropHelper(Me)).Handle
_hwndSource = HwndSource.FromHwnd(handle)
If Not IsNothing(_hwndSource) Then
WindowInitialized(Me)
End If
End Sub
Protected Sub ResizeRectangle_MouseMove(sender As [Object], e As MouseEventArgs)
If Me.WindowState = WindowState.Maximized Then Return
Dim rectangle As Rectangle = TryCast(sender, Rectangle)
Select Case rectangle.Name
Case "top"
Cursor = Cursors.SizeNS
Exit Select
Case "bottom"
Cursor = Cursors.SizeNS
Exit Select
Case "left"
Cursor = Cursors.SizeWE
Exit Select
Case "right"
Cursor = Cursors.SizeWE
Exit Select
Case "topLeft"
Cursor = Cursors.SizeNWSE
Exit Select
Case "topRight"
Cursor = Cursors.SizeNESW
Exit Select
Case "bottomLeft"
Cursor = Cursors.SizeNESW
Exit Select
Case "bottomRight"
Cursor = Cursors.SizeNWSE
Exit Select
Case Else
Exit Select
End Select
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Private Shared Function SendMessage(hWnd As IntPtr, msg As UInt32, wParam As IntPtr, lParam As IntPtr) As IntPtr
End Function
Protected Sub ResizeRectangle_PreviewMouseDown(sender As Object, e As MouseButtonEventArgs)
If Me.WindowState = WindowState.Maximized Then Return
Dim rectangle As Rectangle = TryCast(sender, Rectangle)
Select Case rectangle.Name
Case "top"
Cursor = Cursors.SizeNS
ResizeWindow(ResizeDirection.Top)
Exit Select
Case "bottom"
Cursor = Cursors.SizeNS
ResizeWindow(ResizeDirection.Bottom)
Exit Select
Case "left"
Cursor = Cursors.SizeWE
ResizeWindow(ResizeDirection.Left)
Exit Select
Case "right"
Cursor = Cursors.SizeWE
ResizeWindow(ResizeDirection.Right)
Exit Select
Case "topLeft"
Cursor = Cursors.SizeNWSE
ResizeWindow(ResizeDirection.TopLeft)
Exit Select
Case "topRight"
Cursor = Cursors.SizeNESW
ResizeWindow(ResizeDirection.TopRight)
Exit Select
Case "bottomLeft"
Cursor = Cursors.SizeNESW
ResizeWindow(ResizeDirection.BottomLeft)
Exit Select
Case "bottomRight"
Cursor = Cursors.SizeNWSE
ResizeWindow(ResizeDirection.BottomRight)
Exit Select
Case Else
Exit Select
End Select
End Sub
Private Sub ResizeWindow(direction As ResizeDirection)
SendMessage(_hwndSource.Handle, &H112, New IntPtr(61440 + direction), IntPtr.Zero)
End Sub
Private Enum ResizeDirection
Left = 1
Right = 2
Top = 3
TopLeft = 4
TopRight = 5
Bottom = 6
BottomLeft = 7
BottomRight = 8
End Enum
Protected Sub EgtMainWindow_PreviewMouseMove(sender As Object, e As MouseEventArgs) Handles Me.PreviewMouseMove
If Mouse.LeftButton <> MouseButtonState.Pressed Then
Cursor = Cursors.Arrow
End If
End Sub
'Private Sub MoveRectangle_PreviewMouseDown(sender As Object, e As System.Windows.Input.MouseButtonEventArgs)
' If m_IsMovable And e.LeftButton = MouseButtonState.Pressed Then
' Me.DragMove()
' End If
'End Sub
Private mRestoreIfMove As Boolean = False
Private Sub MoveRectangle_MouseLeftButtonDown(sender As Object, e As System.Windows.Input.MouseButtonEventArgs)
If e.ClickCount = 2 Then
Select Case WindowState
Case Windows.WindowState.Maximized
WindowState = Windows.WindowState.Normal
Case Windows.WindowState.Normal
WindowState = Windows.WindowState.Maximized
End Select
Return
ElseIf WindowState = WindowState.Maximized Then
mRestoreIfMove = True
Return
End If
DragMove()
End Sub
Private Sub MoveRectangle_MouseLeftButtonUp(sender As Object, e As System.Windows.Input.MouseButtonEventArgs)
mRestoreIfMove = False
End Sub
Private Sub MoveRectangle_MouseMove(sender As Object, e As System.Windows.Input.MouseEventArgs)
If mRestoreIfMove Then
mRestoreIfMove = False
Dim percentHorizontal As Double = e.GetPosition(Me).X / ActualWidth
Dim targetHorizontal As Double = RestoreBounds.Width * percentHorizontal
Dim lMousePosition As Win32Point
GetCursorPos(lMousePosition)
Left = lMousePosition.X - targetHorizontal
Top = 0
WindowState = WindowState.Normal
DragMove()
End If
End Sub
#Region "Click events"
Protected Sub MinimizeClick(sender As Object, e As RoutedEventArgs)
WindowState = WindowState.Minimized
End Sub
Protected Sub MaximizeClick(sender As Object, e As RoutedEventArgs)
WindowState = WindowState.Maximized
End Sub
Protected Sub RestoreClick(sender As Object, e As RoutedEventArgs)
If WindowState = WindowState.Normal Then
WindowState = WindowState.Maximized
Else
WindowState = WindowState.Normal
End If
End Sub
Protected Sub CloseClick(sender As Object, e As RoutedEventArgs)
If (Keyboard.Modifiers And ModifierKeys.Alt) = ModifierKeys.Alt OrElse Keyboard.IsKeyDown(Key.F4) Then
Return
End If
If IsNothing(CloseCommand) Then
Me.Close()
End If
End Sub
#End Region
''Evento che lancia una finestra come figlia in modalità dialogo
'Friend Sub TitleBarIcon_PreviewMouseDown()
' If Not IsNothing(AboutBox) And TypeOf AboutBox Is Window Then
' If m_bFirst Then
' AboutBox.ShowDialog()
' Else
' AboutBox.Visibility = Windows.Visibility.Visible
' End If
' End If
'End Sub
#Region "Call Win32 MSG"
Const MONITOR_DEFAULTTONEAREST As Integer = &H2
#Region "DLLImports"
<DllImport("shell32", CallingConvention:=CallingConvention.StdCall)>
Public Shared Function SHAppBarMessage(dwMessage As Integer, ByRef pData As APPBARDATA) As Integer
End Function
<DllImport("user32", SetLastError:=True)>
Friend Shared Function FindWindow(lpClassName As String, lpWindowName As String) As IntPtr
End Function
<DllImport("user32")>
Friend Shared Function GetMonitorInfo(hMonitor As IntPtr, lpmi As MONITORINFO) As Boolean
End Function
<DllImport("user32")>
Friend Shared Function MonitorFromWindow(handle As IntPtr, flags As Integer) As IntPtr
End Function
#End Region
Private Function AdjustWorkingAreaForAutoHide(monitorContainingApplication As IntPtr, mmi As MINMAXINFO) As MINMAXINFO
Dim hwnd As IntPtr = FindWindow("Shell_TrayWnd", Nothing)
If IsNothing(hwnd) Then
Return mmi
End If
Dim monitorWithTaskbarOnIt As IntPtr = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
If Not monitorContainingApplication.Equals(monitorWithTaskbarOnIt) Then
Return mmi
End If
Dim abd As New APPBARDATA()
abd.cbSize = Marshal.SizeOf(abd)
abd.hWnd = hwnd
SHAppBarMessage(CInt(ABMsg.ABM_GETTASKBARPOS), abd)
Dim uEdge As Integer = GetEdge(abd.rc)
Dim autoHide As Boolean = System.Convert.ToBoolean(SHAppBarMessage(CInt(ABMsg.ABM_GETSTATE), abd))
If Not autoHide Then
Return mmi
End If
Select Case uEdge
Case CInt(ABEdge.ABE_LEFT)
mmi.ptMaxPosition.x += 2
mmi.ptMaxTrackSize.x -= 2
mmi.ptMaxSize.x -= 2
Exit Select
Case CInt(ABEdge.ABE_RIGHT)
mmi.ptMaxSize.x -= 2
mmi.ptMaxTrackSize.x -= 2
Exit Select
Case CInt(ABEdge.ABE_TOP)
mmi.ptMaxPosition.y += 2
mmi.ptMaxTrackSize.y -= 2
mmi.ptMaxSize.y -= 2
Exit Select
Case CInt(ABEdge.ABE_BOTTOM)
mmi.ptMaxSize.y -= 2
mmi.ptMaxTrackSize.y -= 2
Exit Select
Case Else
Return mmi
End Select
Return mmi
End Function
Private Function GetEdge(rc As RECT) As Integer
Dim uEdge As Integer = -1
If rc.top = rc.left AndAlso rc.bottom > rc.right Then
uEdge = CInt(ABEdge.ABE_LEFT)
ElseIf rc.top = rc.left AndAlso rc.bottom < rc.right Then
uEdge = CInt(ABEdge.ABE_TOP)
ElseIf rc.top > rc.left Then
uEdge = CInt(ABEdge.ABE_BOTTOM)
Else
uEdge = CInt(ABEdge.ABE_RIGHT)
End If
Return uEdge
End Function
Public Sub WindowInitialized(window As Window)
Dim handle As IntPtr = (New System.Windows.Interop.WindowInteropHelper(window)).Handle
If handle <> System.IntPtr.Zero Then
System.Windows.Interop.HwndSource.FromHwnd(handle).AddHook(New System.Windows.Interop.HwndSourceHook(AddressOf WindowProc))
End If
End Sub
Private Function WindowProc(hwnd As System.IntPtr, msg As Integer, wParam As System.IntPtr, lParam As System.IntPtr, ByRef handled As Boolean) As IntPtr
Select Case msg
Case &H24
WmGetMinMaxInfo(hwnd, lParam)
handled = True
Exit Select
End Select
Return New IntPtr(0)
End Function
Private Sub WmGetMinMaxInfo(hwnd As IntPtr, lParam As IntPtr)
Dim mmi As MINMAXINFO = CType(Marshal.PtrToStructure(lParam, GetType(MINMAXINFO)), MINMAXINFO)
Dim monitorContainingApplication As IntPtr = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
If monitorContainingApplication <> System.IntPtr.Zero Then
Dim monitorInfo As New MONITORINFO()
GetMonitorInfo(monitorContainingApplication, monitorInfo)
Dim rcWorkArea As RECT = monitorInfo.rcWork
Dim rcMonitorArea As RECT = monitorInfo.rcMonitor
mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left)
mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top)
mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left)
mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top)
mmi.ptMaxTrackSize.x = mmi.ptMaxSize.x
'maximum drag X size for the window
mmi.ptMaxTrackSize.y = mmi.ptMaxSize.y
'maximum drag Y size for the window
mmi.ptMinTrackSize.x = CInt(Me.MinWidth)
'minimum drag X size for the window
mmi.ptMinTrackSize.y = CInt(Me.MinHeight)
'minimum drag Y size for the window
'need to adjust sizing if taskbar is set to autohide
mmi = AdjustWorkingAreaForAutoHide(monitorContainingApplication, mmi)
End If
Marshal.StructureToPtr(mmi, lParam, True)
End Sub
Public Enum ABEdge
ABE_LEFT = 0
ABE_TOP = 1
ABE_RIGHT = 2
ABE_BOTTOM = 3
End Enum
Public Enum ABMsg
ABM_NEW = 0
ABM_REMOVE = 1
ABM_QUERYPOS = 2
ABM_SETPOS = 3
ABM_GETSTATE = 4
ABM_GETTASKBARPOS = 5
ABM_ACTIVATE = 6
ABM_GETAUTOHIDEBAR = 7
ABM_SETAUTOHIDEBAR = 8
ABM_WINDOWPOSCHANGED = 9
ABM_SETSTATE = 10
End Enum
<StructLayout(LayoutKind.Sequential)>
Public 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 Boolean
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure MINMAXINFO
Public ptReserved As POINT
Public ptMaxSize As POINT
Public ptMaxPosition As POINT
Public ptMinTrackSize As POINT
Public ptMaxTrackSize As POINT
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Public Class MONITORINFO
Public cbSize As Integer = Marshal.SizeOf(GetType(MONITORINFO))
Public rcMonitor As New RECT()
Public rcWork As New RECT()
Public dwFlags As Integer = 0
End Class
<StructLayout(LayoutKind.Sequential)>
Public Structure POINT
Public x As Integer
Public y As Integer
Public Sub New(x As Integer, y As Integer)
Me.x = x
Me.y = y
End Sub
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=0)>
Public Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
End Structure
#End Region
End Class