Можно ли заставить всплывающее окно игнорировать MenuDropAlignment в приложении WPF / Touch? - PullRequest
16 голосов
/ 17 февраля 2011

В качестве небольшого фона - в Windows есть средство для Touch / TabletPC, с помощью которого оно смещает положение всплывающих окон / меню в зависимости от вашей «руки» (для предотвращения появления меню под вашей рукой).

По сути, это происходит, если вы настроены на «правую руку» (которая, по-видимому, используется по умолчанию после подключения сенсорного устройства), каждое открываемое всплывающее окно искусственно отбрасывается влево - это вызывает серьезные проблемы с макетом. где мы пытаемся выстроить всплывающее окно с элементом, с которого оно «всплыло»:

В настройках планшетного ПК установлено значение Левша - без искусственной коррекции из 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 \ explorer.exe shell ::: {80F3F1D5-FECA-45F3-BC32-752C152E456E}

И посмотрите, какой беспорядок это сделает для себя: -)

Ответы [ 5 ]

3 голосов
/ 28 марта 2013

Установите его в обычный режим для всего приложения:

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

fi.SetValue(null, false);
3 голосов
/ 14 января 2013

Я написал собственное всплывающее окно, которое решает эту проблему: вы можете установить свойство зависимостей 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
0 голосов
/ 28 декабря 2018

Это довольно старый, но я нашел другой способ, если у вас есть, по крайней мере, .net 4.5.

Переопределив шаблоны меню / всплывающих окон, вы можете использовать следующий триггер:

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

Конечно, установите следующее:

  • Истина или Ложь в качестве значения вашего источника данных,
  • Влево или Вправо в качестве значения вашего установщика.

Это важночто привязка использует синтаксис Binding Path = (), а не Binding = {x: static ...}, чтобы вы могли использовать событие StaticPropertyChanged из вашего статического класса.

0 голосов
/ 28 июля 2011

Казалось бы, это просто невозможно, поэтому мы прибегаем к MultiDataTrigger в вопросе для компенсации.

0 голосов
/ 17 февраля 2011

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[] координаты вашего всплывающего окна.

Источник: Отражатель

...