Creating Generic DropDown Control in WPF (Updated)


Following code snippet update to my previous code snippet. In this code snippet now I have added XML doc comments and CustomPopupPlacementCallback implementation.

Imports System.Windows.Controls.Primitives
Imports System.ComponentModel
 
''' <summary>
''' A drop-down control control. Drop-down can be shown by clicking on the control.
''' </summary>
Public Class DropDownControl
    Inherits System.Windows.Controls.Primitives.ToggleButton
 
    ''' <summary>
    ''' Initializes shared resources of <see cref="DropDownControl"/> class.
    ''' </summary>
    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(DropDownControl), New FrameworkPropertyMetadata(GetType(DropDownControl)))
    End Sub
 
    ''' <summary>
    ''' Initializes a new instance of <see cref="DropDownControl"/> class.
    ''' </summary>
    Public Sub New()
        Popup = New Popup()
        Popup.StaysOpen = False
        Popup.Placement = PlacementMode.Custom
        Popup.AllowsTransparency = True
        Me.SetBinding(IsCheckedProperty, "Popup.IsOpen")
    End Sub
 
    ''' <summary>
    ''' Gets or sets the Popup element.
    ''' </summary>
    Public Property Popup As Popup
        Get
            Return GetValue(PopupProperty)
        End Get
        Set(ByVal value As Popup)
            SetValue(PopupProperty, value)
        End Set
    End Property
 
    ''' <summary>
    ''' Identifies the <see cref="Popup"/> dependency property.
    ''' </summary>
    Public Shared ReadOnly PopupProperty As DependencyProperty = _
                           DependencyProperty.Register("Popup", _
                           GetType(Popup), GetType(DropDownControl), _
                           New FrameworkPropertyMetadata(NothingNew PropertyChangedCallback(AddressOf OnPopupChanged)))
 
    ''' <summary>
    ''' Gets or sets the Drop-down element.
    ''' </summary>
    Public Property DropDown As FrameworkElement
        Get
            Return GetValue(DropDownProperty)
        End Get
        Set(ByVal value As FrameworkElement)
            SetValue(DropDownProperty, value)
        End Set
    End Property
 
    ''' <summary>
    ''' Identifies the <see cref="DropDown"/> dependency property.
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared ReadOnly DropDownProperty As DependencyProperty = _
                           DependencyProperty.Register("DropDown", _
                           GetType(FrameworkElement), GetType(DropDownControl), _
                           New FrameworkPropertyMetadata(NothingNew PropertyChangedCallback(AddressOf OnDropDownChanged)))
 
    ''' <summary>
    ''' Represents the callback that is invoked when the value of <see cref="DropDown"/> dependency property changes.
    ''' </summary>
    ''' <param name="d">The <see cref="DropDownControl"/> on which the property has changed value.</param>
    ''' <param name="e">Event data that is issued by any event that tracks changes to the effective value of this property.</param>
    ''' <remarks></remarks>
    Private Shared Sub OnDropDownChanged(ByVal d As System.Windows.DependencyObjectByVal e As System.Windows.DependencyPropertyChangedEventArgs)
        Dim ddc As DropDownControl = d
        If ddc.Popup IsNot Nothing Then
            ddc.Popup.Child = e.NewValue
        End If
    End Sub
 
    ''' <summary>
    ''' Represents the callback that is invoked when the value of <see cref="DropDown"/> dependency property changes.
    ''' </summary>
    ''' <param name="d">The <see cref="DropDownControl"/> on which the property has changed value.</param>
    ''' <param name="e">Event data that is issued by any event that tracks changes to the effective value of this property.</param>
    ''' <remarks></remarks>
    Private Shared Sub OnPopupChanged(ByVal d As System.Windows.DependencyObjectByVal e As System.Windows.DependencyPropertyChangedEventArgs)
        Dim dropdown As DropDownControl = d
        Dim popup As Popup = e.NewValue
        Dim oldPopup As Popup = e.OldValue
        If oldPopup IsNot Nothing Then
            popup.CustomPopupPlacementCallback = Nothing
        End If
        If popup IsNot Nothing Then
            popup.CustomPopupPlacementCallback = New CustomPopupPlacementCallback(AddressOf dropdown.GetCustomPoupPlacement)
        End If
    End Sub
 
    ''' <summary>
    ''' Represents a method that provides custom positioning for a Popup control.
    ''' </summary>
    ''' <param name="popupSize">The System.Windows.Size of the System.Windows.Controls.Primitives.Popup control.</param>
    ''' <param name="targetSize">The System.Windows.Size of the System.Windows.Controls.Primitives.Popup.PlacementTarget.</param>
    ''' <param name="offset">The System.Windows.Point computed from the System.Windows.Controls.Primitives.Popup.HorizontalOffset and System.Windows.Controls.Primitives.Popup.VerticalOffset property values.</param>
    Private Function GetCustomPoupPlacement(ByVal popupSize As System.Windows.SizeByVal targetSize As System.Windows.SizeByVal offset As System.Windows.PointAs CustomPopupPlacement()
        Dim sPoint As Point = Me.PointToScreen(New Point(0, 0))
        Dim tX As Double = 0
        Dim tY As Double = targetSize.Height
 
        If popupSize.Width + sPoint.X > SystemParameters.PrimaryScreenWidth Then
            tX = -(popupSize.Width - targetSize.Width)
        End If
        If popupSize.Height + sPoint.Y > SystemParameters.PrimaryScreenHeight Then
            tY = -popupSize.Height
        End If
 
        Return New CustomPopupPlacement() {New CustomPopupPlacement(New Point(tX, tY), PopupPrimaryAxis.Horizontal)}
    End Function
 
    ''' <summary>
    ''' Called when a control is clicked by the mouse or the keyboard.
    ''' </summary>
    Protected Overrides Sub OnClick()
        MyBase.OnClick()
        Popup.PlacementTarget = Me
        Popup.IsOpen = True
    End Sub
 
End Class


Emoticon Emoticon