2013-08-07 8 views
10

Właśnie przeniosłem komputer do systemu Windows 8 z Windows 7 i podczas działania naszej aplikacji WPF zauważyłem, że nasze wyskakujące okna i/lub podpowiedzi dotyczące WPF są teraz domyślnie w lewym dolnym lewym rogu, a nie w prawym dolnym prawym rogu . Czy ktoś to zauważył? Wiem, że możesz określić ich lokalizację na każdej etykiecie narzędzia w xaml, ale mamy wiele wskazówek i popupów. Chcę wiedzieć, czy istnieje sposób na określenie domyślnej lokalizacji globalnie w aplikacji WPF. Google nie przyniosło wielu wyników na ten temat. Mamy powód, aby utrzymywać je w tej samej pierwotnej domyślnej pozycji (niektóre wyskakujące okienka mają treść względem ich pozycji początkowej).Potwierdzenie WPF z wyskakującymi okienkami

Windows 8: (dolny lewy)

Tool Tip on Win8

Windows 7: (dolny prawy)

Tool Tip on Win7

samego kodu! Standardowy atrybut "tooltip" xaml.

Wszelkie pomysły?

rozwiązany i wysłałem komentarzach


Ok, znalazłem problem. Ma to związek z tabletami/ekranami dotykowymi. (z leworęcznymi .. preferencje praworęczne) Ten drugi link podał powód. Pracuję nad rozwiązaniem, aby rozwiązać ten problem teraz. Wkrótce opublikuję szczegóły!

windows 8 popup location

+0

może również być związany z 4,0 vs 4,5 .net - MSDN robi nie powiedzie się, że zmieniła się domyślna wartość miejsca docelowego ... próbując to zrozumieć. – TravisWhidden

+0

Testowana inna maszyna Win8, wydaje się w porządku. Problem z konfiguracją systemu? – TravisWhidden

+0

możliwy duplikat [windows 8 popup location] (http://stackoverflow.com/questions/12927274/windows-8-popup-location) –

Odpowiedz

9

Ok, dla tych, którzy nie chcą, aby ten występuje w ogóle w ich aplikacji (który był naszym pragnieniem), stworzyliśmy ładny mały trik dla WPF. Działa to dobrze dla nas.

pierwsze:

Kod ten będzie co biegnie który rozwiązuje ten problem:

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; 
    } 
} 

Jednak środowisko może de-walidacji Microsoftu wewnętrzną pamięć tych wartości, więc mamy się podłączyć do WinProc aby to zdobyć. Nie będę pisać kod WinProc, tylko te wiadomości, które są potrzebne:

Są to komunikaty Win32, które de walidacji cache wewnętrzna:

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; 

a szybki snippit która będzie wyznaczać swoje preferencje powrotem. Ponieważ jesteśmy podłączeni do WinProc, będziesz chciał zmienić tę wartość po zakończeniu WinProc z komunikatem na innych programach obsługi. Mamy opóźnienie, aby ponownie ustawić wartość preferencji z powrotem na to, co chcemy.

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

I tak jak to jest kompletne. Mam nadzieję, że to pomoże komuś innemu!

14

Dzięki @TravisWhidden dla rozwiązania. Właśnie zaimplementowałem ulepszoną wersję tego, która słucha wydarzenia StaticPropertyChanged, wkleję to tutaj, ponieważ wydaje się mniej "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

Słodki. To działa również! – TravisWhidden

+0

Sidenote, wymaga to .NET 4.5 – Anders

+0

Dziękuję za to. Bardzo irytujący problem. – CodeOtaku

1

Jeśli nie można stosować roztwory, które zmieniają ten system-wide zachowanie, oto jak to zrobić za pomocą pojedynczego 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"); 
    } 
} 
Powiązane problemy