wpf - style datatrigger
¿Es posible hacer que una ventana emergente ignore MenuDropAlignment en una aplicación WPF/Touch? (4)
Como un poco de fondo: Windows tiene una función para Touch / TabletPCs por el cual cambia la posición de las ventanas emergentes / menús en función de su "lateralidad" (para evitar que el menú aparezca bajo su mano).
Esencialmente, lo que hace es que si está configurado como "diestro" (que parece ser el predeterminado una vez que haya conectado un dispositivo táctil), cada ventana emergente que abra se golpea artificialmente hacia la izquierda; esto provoca problemas de diseño masivo donde intentamos y alinee una ventana emergente con el elemento desde el que "apareció".
Configuración de Tablet PC configurada como zurdo: sin corrección artificial desde Windows
Configuraciones de Tablet PC configuradas para diestros: Windows ajusta artificialmente nuestro posicionamiento
Podemos detectar el ajuste de esta configuración con SystemParameters.MenuDropAlignment , y para ventanas emergentes triviales podemos ajustar esto usando el ancho real de la ventana emergente, pero para ventanas emergentes dinámicas y cuando lanzamos soporte de derecha a izquierda en la mezcla, esto simplemente no funciona. t trabajo.
Actualmente, parece más probable que tengamos que pasar por cada ventana emergente, calcular manualmente un valor para ajustar la patada y agregar algo como esto a cada uno:
<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>
Entonces ... de vuelta a la pregunta :-) ¿Alguien sabe de una forma de detener una ventana emergente de WPF mirando esta configuración?
Para aquellos que no tienen un dispositivo táctil, puede acceder a la configuración de Tablet PC ejecutando:
C: / Windows / explorer.exe shell ::: {80F3F1D5-FECA-45F3-BC32-752C152E456E}
Y mira el lío que te hace a ti mismo :-)
Parece que esto simplemente no es posible, por lo que estamos recurriendo a MultiDataTrigger en la pregunta para compensar.
Escribí una ventana emergente personalizada que resuelve este problema: puede establecer la propiedad de dependencia ForceAlignment y abrirla con el método "Abrir", o puede llamar directamente a los métodos "OpenLeft" y "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
Configúrelo en modo regular para toda su aplicación:
FieldInfo fi = typeof(SystemParameters).GetField("_menuDropAlignment",
BindingFlags.NonPublic | BindingFlags.Static);
fi.SetValue(null, false);
SystemParameters.MenuDropAlignment
se usa en un único método:
System.Windows.Controls.Primitives.Popup.GetPointCombination()
Este método privado tiene una lógica que depende del valor de Popup.Placement
, que es del tipo PlacementMode
:
public enum PlacementMode
{
Absolute,
Relative,
Bottom,
Center,
Right,
AbsolutePoint,
RelativePoint,
Mouse,
MousePoint,
Left,
Top,
Custom
}
En GetPointCombination()
, solo comprueba MenuDropAlignment
cuando PlacementMode
es Relative
, AbsolutePoint
, RelativePoint
o MousePoint
. Si puede usar uno de los otros PlacementModes
entonces no estará sujeto a la verificación MenuDropAlignment
.
Si usa PlacementMode.Custom
, también querrá configurar Popup.CustomPopupPlacementCallback
en un método válido para proporcionar las CustomPopupPlacement[]
de su CustomPopupPlacement[]
.
Fuente: Reflector