2013-08-07 14 views
10

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 WPF e/o suggerimenti sono ora in basso a sinistra di default invece del 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).WPF Handedness con Popup

Windows 8: (In basso a sinistra)

Tool Tip on Win8

Windows 7: (in basso a destra)

Tool Tip on Win7

Stesso codice! Attributo xaml standard "tooltip".

Qualche idea?

risolto e ho postato il 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 location

+0

potrebbe anche essere correlato a 4,0 vs 4,5 .net - MSDN fa non dire che il valore predefinito del posizionamento è cambiato .... cercando di capirlo. – TravisWhidden

+0

Testata un'altra macchina Win8, sembra soddisfacente. Problema di configurazione del sistema? – TravisWhidden

+0

possibile duplicato di [windows 8 popup location] (http://stackoverflow.com/questions/12927274/windows-8-popup-location) –

risposta

9

Ok, per coloro che non vogliono che questo accada a tutti nella loro app (che era il nostro desiderio), Abbiamo creato un piccolo hack piacevole per WPF. Questo funziona bene per noi.

Primo:

Questo codice sarà quello che corre, che 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-convalidare microsofts cache interna di questi valori, quindi dobbiamo agganciare in WinProc per ottenere questo. I wont pubblicare il codice WinProc, solo i messaggi che sono necessari:

Questi sono i messaggi Win32 che de-validare 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 rapida che fisserà la vostra preferenza schiena. 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!

14

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); 
     } 
    } 
+0

Dolce. Funziona anche! – TravisWhidden

+0

Sidenote, richiede .NET 4.5 – Anders

+0

Grazie per questo. Problema molto irritante. – CodeOtaku

1

Se non è possibile utilizzare le soluzioni che alterano il sistema a livello di comportamento, ecco come lo faccio per un singolo popup:

public enum HorizontalPlacement { Left, Right, Center }; 

public enum VerticalPlacement { Top, Bottom, Center }; 

/// <summary> 
/// 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 
/// </summary> 
public static class PopupPlacement 
{ 
    /// <summary> 
    /// Usage: In XAML, add the following to your tooltip: 
    ///  Placement="Custom" CustomPopupPlacementCallback="CustomPopupPlacementCallback" 
    /// and call this method from the CustomPopupPlacementCallback. 
    /// </summary> 
    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"); 
    } 
}