' 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.Runtime.InteropServices Imports System.Windows.Interop Public Class EgtMainWindow 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_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() 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 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 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 #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