Manipolazione WPF con Popups

Ho appena spostato il mio PC su Windows 8 da Windows 7 e mentre eseguivo la nostra applicazione WPF ho notato che i nostri popup e / o suggerimenti per gli strumenti WPF sono ora in basso a sinistra per impostazione predefinita al posto della normale in basso a destra. Qualcuno ha notato questo? So che puoi specificare la loro posizione su ogni suggerimento in xaml, ma abbiamo un sacco di suggerimenti e popup. Voglio sapere se esiste un modo per specificare la posizione predefinita globalmente in un’app WPF. Google non ha prodotto molti risultati su questo argomento. Abbiamo un motivo per mantenerli nella stessa posizione di default originale (alcuni popup hanno contenuti relativi alla loro posizione di avvio).

Windows 8: (in basso a sinistra)

Tool Tip su Win8

Windows 7: (in basso a destra)

Tool Tip su Win7

Stesso codice! Attributo xaml standard “tooltip“.

Qualche idea?

RISOLTO E HO PUBBLICATO I COMMENTI


Ok, ho trovato il problema. Ha a che fare con Tablet PC / Touchscreen. (mancino .. preferenza per mano destra) Questo altro link ha fornito un motivo. Sto lavorando a una soluzione per risolvere questo problema ora. Ill posterò presto i dettagli!

Windows 8 popup posizione

Grazie a @TravisWhidden per la soluzione. Ho appena implementato una versione migliorata di esso che ascolta l’evento StaticPropertyChanged, lo incollo qui perché sembra meno di un “hack”.

private static readonly FieldInfo _menuDropAlignmentField; static MainWindow() { _menuDropAlignmentField = typeof(SystemParameters).GetField("_menuDropAlignment", BindingFlags.NonPublic | BindingFlags.Static); System.Diagnostics.Debug.Assert(_menuDropAlignmentField != null); EnsureStandardPopupAlignment(); SystemParameters.StaticPropertyChanged += SystemParameters_StaticPropertyChanged; } private static void SystemParameters_StaticPropertyChanged(object sender, PropertyChangedEventArgs e) { EnsureStandardPopupAlignment(); } private static void EnsureStandardPopupAlignment() { if (SystemParameters.MenuDropAlignment && _menuDropAlignmentField != null) { _menuDropAlignmentField.SetValue(null, false); } } 

Ok, per quelli che non vogliono che ciò accada nella loro app (che era il nostro desiderio), abbiamo creato un bel trucco per WPF. Questo funziona bene per noi.

Primo:

Questo codice sarà ciò che viene eseguito e risolve il problema:

 public static void SetAlignment() { var ifLeft = SystemParameters.MenuDropAlignment; if (ifLeft) { // change to false var t = typeof(SystemParameters); var field = t.GetField("_menuDropAlignment", BindingFlags.NonPublic | BindingFlags.Static); field.SetValue(null, false); ifLeft = SystemParameters.MenuDropAlignment; } } 

Tuttavia, l’ambiente può de-validare la cache interna di microsofts di questi valori, quindi per ottenere questo dobbiamo collegarci a WinProc. Non invierò il codice WinProc, solo i messaggi necessari:

Questi sono i messaggi Win32 che decodificheranno la cache interna:

 private const int WM_WININICHANGE = 0x001A; private const int WM_DEVICECHANGE = 0x219; private const int WM_DISPLAYCHANGE = 0x7E; private const int WM_THEMECHANGED = 0x031A; private const int WM_SYSCOLORCHANGE = 0x15; 

E lo snippit veloce che imposterà la tua preferenza. Perché siamo agganciati a WinProc, vorrete cambiare questo valore dopo che WinProc ha finito con il messaggio su altri gestori. Abbiamo un ritardo per reimpostare il valore di preferenza su ciò che vogliamo.

 if (msg == WM_WININICHANGE || msg == WM_DEVICECHANGE || msg == WM_DISPLAYCHANGE || msg == WM_THEMECHANGED || msg == WM_SYSCOLORCHANGE) { Timer timer = null; timer = new Timer((x) => { WpfHelperHacks.SetAlignment(); timer.Dispose(); },null, TimeSpan.FromMilliseconds(2), TimeSpan.FromMilliseconds(-1)); } 

E proprio così è completo. Spero che questo aiuti qualcun’altro!

Se non puoi usare soluzioni che alterano questo comportamento a livello di sistema, ecco come lo faccio per un singolo popup:

 public enum HorizontalPlacement { Left, Right, Center }; public enum VerticalPlacement { Top, Bottom, Center }; ///  /// In WPF, PopUps pop up in different places on different machines (due to different "handedness" on touch-enabled screens. This fixes it. /// See Also: http://social.msdn.microsoft.com/Forums/vstudio/en-US/19ef3d33-01e5-45c5-a845-d64f9231001c/popup-positioningalignments?forum=wpf ///  public static class PopupPlacement { ///  /// Usage: In XAML, add the following to your tooltip: /// Placement="Custom" CustomPopupPlacementCallback="CustomPopupPlacementCallback" /// and call this method from the CustomPopupPlacementCallback. ///  public static CustomPopupPlacement[] PlacePopup(Size popupSize, Size targetSize, Point offset, VerticalPlacement verticalPlacement, HorizontalPlacement horizontalPlacement) { Point p = new Point { X = GetHorizontalOffset(popupSize, targetSize, horizontalPlacement), Y = GetVerticalOffset(popupSize, targetSize, verticalPlacement) }; return new[] { new CustomPopupPlacement(p, PopupPrimaryAxis.Horizontal) }; } private static double GetVerticalOffset(Size popupSize, Size targetSize, VerticalPlacement verticalPlacement) { switch (verticalPlacement) { case VerticalPlacement.Top: return -popupSize.Height; case VerticalPlacement.Bottom: return targetSize.Height; case VerticalPlacement.Center: return -(popupSize.Height/ 2) + targetSize.Height / 2; } throw new ArgumentOutOfRangeException("verticalPlacement"); } private static double GetHorizontalOffset(Size popupSize, Size targetSize, HorizontalPlacement horizontalPlacement) { switch (horizontalPlacement) { case HorizontalPlacement.Left: return -popupSize.Width; case HorizontalPlacement.Right: return 0; case HorizontalPlacement.Center: return -(popupSize.Width / 2) + targetSize.Width / 2; } throw new ArgumentOutOfRangeException("horizontalPlacement"); } }