' 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. ' ' ' Imports System.Windows.Controls.Primitives Imports System.Windows.Interop Imports System.Runtime.InteropServices Imports EgtWPFLib5 Public Class EgtCustomWindow Inherits System.Windows.Window _ Friend Shared Function GetCursorPos(ByRef pt As Win32Point) As Boolean End Function _ 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_RestoreButton As Button Private m_IsResizable As Boolean Private m_IsMovable As Boolean ' Proprietà che permette di impostare l'altezza della TitleBar Public Shared ReadOnly TitleBarHeightProperty As DependencyProperty = DependencyProperty.Register("TitleBarHeight", GetType(Double), GetType(EgtCustomWindow), New PropertyMetadata(10.0)) Public Property TitleBarHeight() As Double Get Return CType(GetValue(TitleBarHeightProperty), Double) End Get Set(ByVal value As Double) SetValue(TitleBarHeightProperty, value) End Set End Property ' Proprietà che permette di impostare l'altezza della TitleBar Public Shared ReadOnly CloseCommandProperty As DependencyProperty = DependencyProperty.Register("CloseCommand", GetType(ICommand), GetType(EgtCustomWindow), 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 l'altezza della TitleBar Public Shared ReadOnly CloseCommandParameterProperty As DependencyProperty = DependencyProperty.Register("CloseCommandParameter", GetType(Object), GetType(EgtCustomWindow), New PropertyMetadata(Nothing)) Public Property CloseCommandParameter() As Object Get Return GetValue(CloseCommandParameterProperty) End Get Set(ByVal value As Object) SetValue(CloseCommandParameterProperty, value) End Set End Property ' Proprietà che permette di impostare la Window lanciata sul click dell'icona della TitleBar Public Shared ReadOnly AboutBoxProperty As DependencyProperty = DependencyProperty.Register("AboutBox", GetType(Window), GetType(EgtCustomWindow), New PropertyMetadata(Nothing)) Public Property AboutBox() As Window Get Return DirectCast(GetValue(AboutBoxProperty), Window) End Get Set(ByVal value As Window) SetValue(AboutBoxProperty, 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(EgtCustomWindow), 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(EgtCustomWindow), 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 uno UserControl per aggiungere elementi alla TitleBar Public Shared ReadOnly TitleBarBrushProperty As DependencyProperty = DependencyProperty.Register("TitleBarBrush", GetType(Windows.Media.Brush), GetType(EgtCustomWindow), New PropertyMetadata(Windows.Media.Brushes.White)) Public Property TitleBarBrush() As Windows.Media.Brush Get Return DirectCast(GetValue(TitleBarBrushProperty), Windows.Media.Brush) End Get Set(ByVal value As Windows.Media.Brush) SetValue(TitleBarBrushProperty, value) End Set End Property ' Proprietà che permette di attivare e disattivare il resize della finestra Public Shared ReadOnly IsResizableProperty As DependencyProperty = DependencyProperty.Register("IsResizable", GetType(Boolean), GetType(EgtCustomWindow), New PropertyMetadata(True)) Public Property IsResizable() As Boolean Get Return CBool(GetValue(IsResizableProperty)) End Get Set(ByVal value As Boolean) SetValue(IsResizableProperty, value) m_IsResizable = value End Set End Property ' Proprietà che permette di attivare e disattivare lo spostamento della finestra Public Shared ReadOnly IsMovableProperty As DependencyProperty = DependencyProperty.Register("IsMovable", GetType(Boolean), GetType(EgtCustomWindow), New PropertyMetadata(True)) Public Property IsMovable() As Boolean Get Return CBool(GetValue(IsMovableProperty)) End Get Set(ByVal value As Boolean) SetValue(IsMovableProperty, value) m_IsMovable = value End Set End Property ' Proprietà che permette di attivare e disattivare lo spostamento della finestra Public Shared ReadOnly IsMinimizableProperty As DependencyProperty = DependencyProperty.Register("IsMinimizable", GetType(Boolean), GetType(EgtCustomWindow), New PropertyMetadata(True)) Public Property IsMinimizable() As Boolean Get Return CBool(GetValue(IsMinimizableProperty)) End Get Set(ByVal value As Boolean) SetValue(IsMinimizableProperty, value) m_IsMovable = value End Set End Property ' Proprietà che permette di attivare e disattivare il bottone di chiusura della finestra Public Shared ReadOnly IsClosableProperty As DependencyProperty = DependencyProperty.Register("IsClosable", GetType(Boolean), GetType(EgtCustomWindow), New PropertyMetadata(True)) Public Property IsClosable() As Boolean Get Return CBool(GetValue(IsClosableProperty)) End Get Set(ByVal value As Boolean) SetValue(IsClosableProperty, value) If Not value Then IsMinimizable = False End If 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(EgtCustomWindow), New FrameworkPropertyMetadata(GetType(EgtCustomWindow))) End Sub Sub New() End Sub Sub New(Owner As Window) Me.Owner = Owner End Sub Public Overrides Sub OnApplyTemplate() MyBase.OnApplyTemplate() m_IsResizable = IsResizable m_IsMovable = IsMovable ' 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 If Not IsNothing(TitleBarIcon) Then AddHandler TitleBarIcon.PreviewMouseDown, AddressOf TitleBarIcon_PreviewMouseDown Else TitleBarIcon.Visibility = Windows.Visibility.Collapsed End If Dim minimizeButton As Button = TryCast(GetTemplateChild("minimizeButton"), Button) If minimizeButton IsNot Nothing Then AddHandler minimizeButton.Click, AddressOf MinimizeClick End If m_RestoreButton = TryCast(GetTemplateChild("restoreButton"), Button) If m_RestoreButton IsNot Nothing Then AddHandler m_RestoreButton.Click, AddressOf RestoreClick End If If Not IsMinimizable Then minimizeButton.Visibility = Windows.Visibility.Collapsed m_RestoreButton.Visibility = Windows.Visibility.Collapsed End If Dim closeButton As Button = TryCast(GetTemplateChild("closeButton"), Button) If closeButton IsNot Nothing Then AddHandler closeButton.Click, AddressOf CloseClick End If If Not IsClosable Then closeButton.Visibility = Windows.Visibility.Collapsed End If End Sub Private Sub EgtCustomWindow_StateChanged(sender As Object, e As EventArgs) Handles Me.StateChanged If WindowState = Windows.WindowState.Maximized Then m_RestoreButton.Content = 2 Else m_RestoreButton.Content = 1 End If End Sub Private Sub EgtCustomWindow_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 m_IsResizable Then 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 If End Sub _ 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 m_IsResizable Then 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 If End Sub Private Sub ResizeWindow(direction As ResizeDirection) If m_IsResizable Then SendMessage(_hwndSource.Handle, &H112, New IntPtr(61440 + direction), IntPtr.Zero) End If 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 IsResizable Then 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 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 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 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" _ Public Shared Function SHAppBarMessage(dwMessage As Integer, ByRef pData As APPBARDATA) As Integer End Function _ Friend Shared Function FindWindow(lpClassName As String, lpWindowName As String) As IntPtr End Function _ Friend Shared Function GetMonitorInfo(hMonitor As IntPtr, lpmi As MONITORINFO) As Boolean End Function _ 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 _ 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 _ 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 _ 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 _ 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 _ 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