这个问题与帖子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
您的问题无法重现。但是,我相信当您通过将
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