我刚刚将我的PC从Windows 7移动到Windows 8,在运行我们的WPF应用程序时,我注意到我们的WPF弹出窗口和或工具提示现在默认在左下角,而不是正常的右下角。 有人注意到这一点吗? 我知道你可以在xaml中指定每个工具提示的位置,但我们有很多工具提示和弹出窗口。 我想知道是否有一种方法可以在WPF应用程序中全局指定默认位置。Google在这个问题上没有得到很多结果。我们有理由让它们保持在原来的默认位置上(有些弹出窗口的内容与它们的启动位置相对)。
Windows 8。(左下角)
Windows 7: (右下角)
同样的代码! 标准的 "tooltip "xaml属性。
有什么想法吗?
解决了,我发了评论。
好了,我已经找到了问题所在。它与平板电脑Touchscreens有关。(左手......右手的偏好)这个其他的链接提供了一个原因。我现在正在研究解决这个问题的办法。我很快就会把细节发布出来!
谢谢@TravisWhidden的解决方案。刚刚实现了一个改进的版本,它监听到了 StaticPropertyChanged
事件,我把它贴在这里,因为它看起来不是一个 "黑客"。
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);
}
}
好吧,对于那些不希望在他们的应用程序中发生这种情况的人(这是我们的愿望),我们已经为WPF创建了一个不错的小黑客。 这对我们来说很有效。
首先,这段代码将是运行修复WPF的代码。
这段代码将被运行,从而解决这个问题。
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;
}
}
然而,环境可以去验证microsofts内部缓存的这些值,所以我们必须挂钩到WinProc得到这个。 我不会发布WinProc代码,只发布需要的消息。
这些是Win32的消息,它可以去掉内部缓存的验证。
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;
还有一个快速的代码,可以把你的偏好设置回来。 因为我们是挂在WinProc上的,所以你要在WinProc完成对其他处理程序的消息后更改这个值。 我们有一个延迟来重新设置偏好值到我们想要的值。
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));
}
就这样它就完成了。 希望这对别人有帮助!
如果你不能使用改变整个系统的这种行为的解决方案,下面是我对单个弹出窗口的做法。
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");
}
}