是否可以在 WPF / Touch 应用程序中弹出一个忽略 MenuDropAlignment 的窗口?

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

作为一点背景知识 - Windows 有一个针对触摸/平板电脑的功能,它可以根据您的“惯用手”移动弹出窗口/菜单的位置(以防止菜单出现在您的手下)。

本质上,如果您设置为“右手”(连接触摸设备后似乎默认为右手),您打开的每个弹出窗口都会被人为地踢到左侧 - 这会导致严重的布局问题,我们尝试将弹出窗口与其“从中弹出”的项目对齐:

平板电脑设置设置为左手 - 无需从 Windows 进行人工修正 Tablet PC Settings set to Left handed - no artificial correction from Windows

平板电脑设置设置为右手 - Windows 人为调整我们的位置 Tablet PC Settings set to Right handed - Windows artificially adjusts our positioning

我们可以使用 SystemParameters.MenuDropAlignment 检测此设置的设置,对于简单的弹出窗口,我们可以使用弹出窗口的实际宽度来调整它 - 但对于动态弹出窗口,当我们将从右到左的支持添加到混合中时,这只是不起作用。

目前看来,我们更有可能必须检查每个弹出窗口,手动计算出一个值来调整踢,并向每个弹出窗口添加类似的内容:

<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding Source={x:Static SystemParameters.MenuDropAlignment}}" Value="True"/>
        <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=FlowDirection}" Value="RightToLeft"/>
    </MultiDataTrigger.Conditions>
    <MultiDataTrigger.Setters>
        <Setter Property="HorizontalOffset" Value="-50"/> <!-- Set to arbitrary value to test -->
    </MultiDataTrigger.Setters>
</MultiDataTrigger>

所以..回到问题:-) 有谁知道有什么方法可以阻止 WPF 弹出窗口查看此设置吗?

对于没有触摸设备的用户,您可以通过运行以下命令访问平板电脑设置:

C:\Windows xplorer.exe shell:::{80F3F1D5-FECA-45F3-BC32-752C152E456E}

看看它给你自己带来的混乱:-)

wpf xaml touch multi-touch multidatatrigger
6个回答
3
投票

我编写了一个自定义弹出窗口来解决这个问题:您可以设置 ForceAlignment 依赖属性并使用“Open”方法将其打开,也可以直接调用“OpenLeft”和“OpenRight”方法。

Public Class CustomPopup

Inherits Primitives.Popup
Private Shared moFI As Reflection.FieldInfo = GetType(SystemParameters).GetField("_menuDropAlignment", Reflection.BindingFlags.NonPublic + Reflection.BindingFlags.Static)

Public Enum enuForceAlignment
    None = 0
    Left
    Right
End Enum

Public Property ForceAlignment As enuForceAlignment
    Get
        Return GetValue(ForceAlignmentProperty)
    End Get

    Set(ByVal value As enuForceAlignment)
        SetValue(ForceAlignmentProperty, value)
    End Set
End Property
Public Shared ReadOnly ForceAlignmentProperty As DependencyProperty = _
                       DependencyProperty.Register("ForceAlignment", _
                       GetType(enuForceAlignment), GetType(CustomPopup), _
                       New FrameworkPropertyMetadata(enuForceAlignment.None))

Public Sub Open()
    Select Case ForceAlignment
        Case enuForceAlignment.Left
            OpenLeft()
        Case enuForceAlignment.Right
            OpenRight()
        Case Else
            IsOpen = True
    End Select
End Sub
Public Sub OpenRight()
    _Open(False)
End Sub
Public Sub OpenLeft()
    _Open(True)
End Sub
Private Sub _Open(paMenuDropAlignment As Boolean)
    If SystemParameters.MenuDropAlignment <> paMenuDropAlignment Then
        moFI.SetValue(Nothing, paMenuDropAlignment)
        IsOpen = True
        moFI.SetValue(Nothing, Not paMenuDropAlignment)
    Else
        IsOpen = True
    End If
End Sub
End Class

2
投票

将整个应用程序设置为常规模式:

FieldInfo fi = typeof(SystemParameters).GetField("_menuDropAlignment",
   BindingFlags.NonPublic | BindingFlags.Static);

fi.SetValue(null, false);

1
投票

这已经很老了,但如果你至少有 .net 4.5,我找到了另一种方法。

通过覆盖菜单项/弹出窗口模板,您可以使用以下触发器:

<DataTrigger Binding="{Binding Path=(SystemParameters.MenuDropAlignment)}" Value="[True/False]">
    <Setter TargetName="Popup" Property="Placement" Value="[Left/Right]"/>
</DataTrigger>

当然,设置以下内容:

  • 您的数据触发值是真是假,
  • Left 或 Right 作为您的 setter 值。

绑定使用 Binding Path=() 语法而不是 Binding={x:static ...} 非常重要,这样您就可以使用静态类中的 StaticPropertyChanged 事件。


0
投票

这似乎是不可能的,因此我们求助于问题中的 MultiDataTrigger 来进行补偿。


0
投票

SystemParameters.MenuDropAlignment
用于单一方法:

System.Windows.Controls.Primitives.Popup.GetPointCombination()

此私有方法的逻辑取决于

Popup.Placement
的值,其类型为
PlacementMode
:

public enum PlacementMode
{
    Absolute,
    Relative,
    Bottom,
    Center,
    Right,
    AbsolutePoint,
    RelativePoint,
    Mouse,
    MousePoint,
    Left,
    Top,
    Custom
}

GetPointCombination()
中,仅当
MenuDropAlignment
PlacementMode
Relative
AbsolutePoint
RelativePoint
时才检查
MousePoint
。如果您可以使用其他
PlacementModes
之一,那么您将不会受到
MenuDropAlignment
检查。

如果您使用

PlacementMode.Custom
,那么您还需要将
Popup.CustomPopupPlacementCallback
设置为有效方法,以便提供弹出窗口的
CustomPopupPlacement[]
坐标。

来源:反射器


0
投票

除了 Julican 的 answer 如果您不使用 StaticPropertyChanged 事件

<Popup.Style>
    <Style TargetType="Popup">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Source={x:Static SystemParameters.MenuDropAlignment}}" Value="1">
                <Setter Property="Placement" Value="Right"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Source={x:Static SystemParameters.MenuDropAlignment}}" Value="0">
                <Setter Property="Placement" Value="Left"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Popup.Style>

在上面的代码中,值可能会有所不同,具体取决于您想要的...... 另外,请确保您没有将 Placement 属性放置在弹出窗口上:

<Popup
    ...
    Placement="Right"
    ...
/>
© www.soinside.com 2019 - 2024. All rights reserved.