【问题标题】:WPF Handedness with Popups带有弹出窗口的 WPF 惯用手
【发布时间】:2013-08-09 10:22:33
【问题描述】:

我刚刚将我的 PC 从 Windows 7 移动到 Windows 8,并且在运行我们的 WPF 应用程序时,我注意到我们的 WPF 弹出窗口和/或工具提示现在默认位于左下角,而不是正常的右下角。有没有人注意到这一点?我知道您可以在 xaml 中的每个工具提示上指定它们的位置,但我们有很多工具提示和弹出窗口。我想知道是否有办法在 WPF 应用程序中全局指定默认位置。谷歌在这个主题上没有产生很多结果。我们有理由将它们保持在相同的原始默认位置(某些弹出窗口的内容相对于它们的启动位置)。

Windows 8:(左下)

Windows 7:(右下)

相同的代码!标准“工具提示”xaml 属性。

有什么想法吗?

已解决,我发表了评论


好的,我找到了问题。它与平板电脑/触摸屏有关。 (左撇子.. 右撇子偏好)这个其他链接提供了一个原因。我现在正在研究解决此问题的解决方案。我会尽快发布详细信息!

windows 8 popup location

【问题讨论】:

  • 也可能与 4.0 vs 4.5 .net 相关——MSDN 并没有说placement 的默认值已经改变......试图弄清楚这一点。
  • 测试了另一台Win8机器,看起来不错。系统配置问题?
  • windows 8 popup location的可能重复

标签: .net wpf xaml windows-8 tooltip


【解决方案1】:

感谢@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);
    }
}

【讨论】:

  • 旁注,这需要 .NET 4.5
  • 谢谢你。非常烦人的问题。
【解决方案2】:

好的,对于那些根本不希望在他们的应用程序中发生这种情况的人(这是我们的愿望),我们为 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;
    }
}

但是,环境可以取消验证这些值的 Microsoft 内部缓存,因此我们必须挂钩到 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));
}

就这样完成了。我希望这对其他人有帮助!

【讨论】:

    【解决方案3】:

    如果您无法使用在整个系统范围内改变此行为的解决方案,以下是我为单个弹出窗口执行此操作的方法:

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

    【讨论】:

    • 这在某些情况下不起作用。例如,如果您希望弹出窗口相对于鼠标指针打开,因为从自定义例程返回的点始终相对于 PlacementTarget 坐标,我找不到如何将鼠标指针作为 PlacementTarget。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    • 2012-07-15
    • 2017-12-28
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多