MenuItem SubMenu 出现在 ContextMenu 的左侧而不是默认的

问题描述 投票:0回答:1

这个问题与帖子here相关 - 原来的问题已经解决,但随后又出现了另一个问题。

如您所见,菜单项出现在错误的一侧

由于上一个问题与另一个控制库相关,我用一个最小的示例对其进行了测试......

打开一个针对 .NET 8 的新 MVC 项目。为主窗口上的网格命名,然后添加一个带有按钮的工具栏和一个数据网格。依次将 ContextMenu 应用于每个并获得相同的行为。

Private Sub MainWindow_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized

For i As Integer = 0 To 2
    Dim vRow As New RowDefinition
    If i = 1 Then
        vRow.Height = New GridLength(35, GridUnitType.Star)


    Else
        vRow.Height = New GridLength(35)
    End If
    TestGrid.RowDefinitions.Add(vRow)
Next

Dim vToolBar As New ToolBar
With vToolBar

End With
Grid.SetRow(vToolBar, 0)
TestGrid.Children.Add(vToolBar)

Dim vButton As New Button
With vButton
    .Content = "Test"
    .ContextMenu = ReturnContexMenu()
End With
vToolBar.Items.Add(vButton)

Dim vDG As New DataGrid
With vDG
    '  .ContextMenu = ReturnContexMenu()
End With
Grid.SetRow(vDG, 1)
TestGrid.Children.Add(vDG)

End Sub 

...这是上下文菜单

Private Function ReturnContexMenu() As ContextMenu
Try
    Dim FlagMI As New MenuItem
    With FlagMI
        .Header = "Quick Flag"
        .Name = "FlagMI"
    End With

    Dim MarkReadMI As New MenuItem
    With MarkReadMI
        .Header = "Mark as read"
        .Name = "MarkReadMI"
    End With

    Dim MarkUnreadMI As New MenuItem
    With MarkUnreadMI
        .Header = "Mark as unread"
        .Name = "MarkUnreadMI"
    End With

    Dim MarkAsMI As New MenuItem
    With MarkAsMI
        .Header = "Mark as"
        .Items.Add(MarkReadMI)
        .Items.Add(MarkUnreadMI)
    End With

    Dim vMainContext As New ContextMenu
    With vMainContext
        .Name = "MainContextMenu"
        .Items.Add(FlagMI)
        .Items.Add(MarkAsMI)
    End With

    Return vMainContext
Catch ex As Exception

    Return Nothing
End Try
End Function

我尝试为 MenuItem 添加一个类,并添加 Primatives.PlacementMode 的 DependencyProperty 并将默认值设置为 PlacementMode.Right - 事实上我尝试了所有设置,但没有效果。

Public Class MIx
Inherits System.Windows.Controls.MenuItem

Public Shared ReadOnly HoldingItem As DependencyProperty = DependencyProperty.Register(
    name:="IsHoldingItem", propertyType:=GetType(Primitives.PlacementMode), ownerType:=GetType(MIx),
    typeMetadata:=New FrameworkPropertyMetadata(defaultValue:=PlacementMode.Right))

Protected Overrides Sub OnInitialized(e As EventArgs)
    MyBase.OnInitialized(e)
    Style = Nothing



End Sub

Public Property IsHoldingItem As Primitives.PlacementMode
    Get
        Return GetValue(HoldingItem)
    End Get
    Set(value As Primitives.PlacementMode)
        SetValue(HoldingItem, value)
    End Set
End Property
End Class
wpf contextmenu menuitem
1个回答
0
投票

您的问题无法重现。但是,我相信当您通过将

Popup
设置为
Popup.Placement
来手动控制内部
PlacementMode.Custom
的位置时,可以针对您的特殊情况进行修复:

PositionableMenuItem.vb
我们扩展

MenuItem
来优雅地处理子项的自定义定位。
自定义
PositionableMenuItem
检索其内部
Popup
并将
Popup.Placement
属性设置为
PlacemmentMode.Custom
。这使得
Popup
能够调用我们定义的
Popup.CustomPopupPlacementCallback
,以便手动对齐
Popup
(子菜单项)。

使用新的

PositionableMenuItem.ChildPlacement
属性允许客户端选择位置(当前仅支持左、上、右和下) - 请参阅下面的示例。

Public Class PositionableMenuItem
    Inherits MenuItem

    Public Shared ReadOnly ChildPlacementProperty As DependencyProperty = DependencyProperty.Register("ChildPlacement", GetType(PlacementMode), GetType(PositionableMenuItem), New FrameworkPropertyMetadata(PlacementMode.Right))

    Public Property ChildPlacement As PlacementMode
        Get
            Return CType(GetValue(ChildPlacementProperty), PlacementMode)
        End Get
        Set(ByVal value As PlacementMode)
            Return SetValue(ChildPlacementProperty, value)
        End Set
    End Property

    Private Property PART_Popup As Popup

    Public Overrides Sub OnApplyTemplate()
        MyBase.OnApplyTemplate()
        Me.PART_Popup = TryCast(GetTemplateChild("PART_Popup"), Popup)
        If TypeOf Me.PART_Popup Is [not] Then Nothing

        If True Then
            Me.PART_Popup.CustomPopupPlacementCallback += AddressOf OnChildItemHostPlacementChanged
            Me.PART_Popup.Placement = PlacementMode.Custom
        End If
    End Sub

    Private Function OnChildItemHostPlacementChanged(ByVal popupSize As Size, ByVal targetSize As Size, ByVal offset As Point) As CustomPopupPlacement()
        Dim parent = CType(Me.Parent, Control)
        Dim parentPadding As Thickness = parent.Padding
        Dim additionalTargetWidth As Double = parentPadding.Left + parentPadding.Right + parent.BorderThickness.Right
        Dim additionalTargetHeight As Double = parentPadding.Top + parentPadding.Bottom + parent.BorderThickness.Bottom
        Dim horizontalOffset As Double = 0
        Dim verticalOffset As Double = 0

        Select Case Me.ChildPlacement
            Case PlacementMode.Bottom
                verticalOffset = targetSize.Height + additionalTargetHeight
                horizontalOffset -= parentPadding.Left
            Case PlacementMode.Right
                horizontalOffset = targetSize.Width + additionalTargetWidth
            Case PlacementMode.Left
                horizontalOffset -= popupSize.Width + parentPadding.Left
            Case PlacementMode.Top
                verticalOffset = -popupSize.Height
                horizontalOffset = -parentPadding.Left
            Case Else
                Throw New NotSupportedException()
        End Select

        Dim location = New Point(horizontalOffset, verticalOffset)
        Dim primaryAxis As PopupPrimaryAxis = If(horizontalOffset > 0, PopupPrimaryAxis.Horizontal, PopupPrimaryAxis.Vertical)
        Dim placement = New CustomPopupPlacement(location, primaryAxis)
        Return {placement}
    End Function

    Protected Overrides Sub OnInitialized(ByVal e As EventArgs)
        MyBase.OnInitialized(e)
        Me.Style = Nothing
    End Sub
End Class

使用示例

您可以使用

PositionableMenuItem
替换所有
MenuItem
元素,或者仅将其用于那些具有子项的
MenuItem
元素。

Private Function ReturnContexMenu() As ContextMenu
    Try
        Dim FlagMI As MenuItem = New PositionableMenuItem()

        If True Then
            Dim withBlock = FlagMI
            withBlock.Header = "Quick Flag"
            withBlock.Name = "FlagMI"
        End If

        Dim MarkReadMI As MenuItem = New PositionableMenuItem()

        If True Then
            Dim withBlock = MarkReadMI
            withBlock.Header = "Mark as read"
            withBlock.Name = "MarkReadMI"
        End If

        Dim MarkUnreadMI As MenuItem = New PositionableMenuItem()

        If True Then
            Dim withBlock = MarkUnreadMI
            withBlock.Header = "Mark as unread"
            withBlock.Name = "MarkUnreadMI"
        End If

        Dim MarkAsMI As MenuItem = New PositionableMenuItem() With {
            .ChildPlacement = PlacementMode.Right
        }

        If True Then
            Dim withBlock = MarkAsMI
            withBlock.Header = "Mark as"
            withBlock.Items.Add(MarkReadMI)
            withBlock.Items.Add(MarkUnreadMI)
        End If

        Dim vMainContext As ContextMenu = New ContextMenu()

        If True Then
            Dim withBlock = vMainContext
            withBlock.Name = "MainContextMenu"
            withBlock.Items.Add(MarkAsMI)
            withBlock.Items.Add(FlagMI)
        End If

        Return vMainContext
    Catch ex As Exception
        Return Nothing
    End Try
End Function
© www.soinside.com 2019 - 2024. All rights reserved.