【问题标题】:WPF - Expand control from left edge to window edgeWPF - 将控件从左边缘扩展到窗口边缘
【发布时间】:2021-08-26 13:03:11
【问题描述】:

我目前正在开发一个屏幕 (C#/WPF),它使用 Popup 控件作为工具提示,以提供附加功能(例如复制和粘贴数据)。当单元格悬停在网格视图中时,弹出窗口会显示。我想要完成的是在单元格正下方显示弹出窗口,并允许它向右扩展但不超过屏幕边缘。

到目前为止,我已经能够让它显示在单元格下方并成为单元格的确切宽度。但是,我无法让它扩展到屏幕右侧。我所有的尝试要么没有结果,要么弹出窗口扩大了屏幕的整个宽度。

我一直在尝试将SystemParameters 属性与element.PointToScreen(new Point(0, 0)) 结合使用,但没有成功。我还尝试使用PresentationSource.FromVisual(gridCell) 进行一些操作,并使用source.CompositionTarget.TransformFromDevice.Transform() 获得目标点,但同样没有成功。

显示位于特定点并扩展(向右)到屏幕边缘的 Popup 控件的最简单方法是什么? TIA

【问题讨论】:

    标签: c# wpf popup wpf-positioning


    【解决方案1】:

    我认为,您所需要的一切 - 弹出位置校正。 您可以定义自定义行为。 我解决了类似的问题,想和你分享我的代码。 我相信您可以更改它以获得必要的行为。

    using System;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Controls.Primitives;
    using System.Windows.Interactivity;
    
    namespace YourNameSpace
    {
        public class PopupExtendedPlacementBehavior : Behavior<Popup>
        {
            private static DependencyPropertyDescriptor PopupChildDescriptor
                = DependencyPropertyDescriptor.FromProperty(Popup.ChildProperty, typeof(Popup));
    
            private static FrameworkPropertyMetadata PlacementMetadata
                = new FrameworkPropertyMetadata(ExtendedPlacementMode.Default);
    
            public static DependencyProperty PlacementProperty
                = DependencyProperty.Register("Placement", typeof(ExtendedPlacementMode), typeof(PopupExtendedPlacementBehavior), PlacementMetadata);
    
            private static FrameworkPropertyMetadata IndentFromTargetMetadata
                = new FrameworkPropertyMetadata(0.0);
    
            public static DependencyProperty IndentFromTargetProperty
                = DependencyProperty.Register("IndentFromTarget", typeof(double), typeof(PopupExtendedPlacementBehavior), IndentFromTargetMetadata);
            
            public ExtendedPlacementMode Placement
            {
                get => (ExtendedPlacementMode)GetValue(PlacementProperty);
                set => SetValue(PlacementProperty, value);
            }
            public double IndentFromTarget
            {
                get => (double)GetValue(IndentFromTargetProperty);
                set => SetValue(IndentFromTargetProperty, value);
            }
    
            protected override void OnAttached()
            {
                base.OnAttached();
    
                AssociatedObject.Opened += OnChangePlacement;
                AssociatedObject.SizeChanged += OnChangePlacement;
    
                PopupChildDescriptor.AddValueChanged(AssociatedObject, OnChangePlacement);
            }
    
            protected override void OnDetaching()
            {
                AssociatedObject.Opened -= OnChangePlacement;
                AssociatedObject.SizeChanged -= OnChangePlacement;
    
                PopupChildDescriptor.RemoveValueChanged(AssociatedObject, OnChangePlacement);
    
                base.OnDetaching();
            }
    
            private void OnChangePlacement(object sender, EventArgs e)
            {
                if (CanSetPlacement())
                {
                    SetPlacement(Placement);
                }
            }
    
            private bool CanSetPlacement()
            {
                return
                    AssociatedObject.Placement == PlacementMode.Bottom
                    ||
                    AssociatedObject.Placement == PlacementMode.Top 
                    ||
                    AssociatedObject.Placement == PlacementMode.Right
                    ||
                    AssociatedObject.Placement == PlacementMode.Left;
            }
    
            private void SetPlacement(ExtendedPlacementMode mode)
            {
                var offset = new Point();
    
                switch (mode)
                {
                    case ExtendedPlacementMode.Default:
                        return;
                    case ExtendedPlacementMode.Left | ExtendedPlacementMode.Top:
                        AssociatedObject.Placement = PlacementMode.Left;
                        offset = GetOffset(AssociatedObject, GetTopOffset);
                        offset.X -= IndentFromTarget;
                        offset.Y -= IndentFromTarget;
                        break;
                    case ExtendedPlacementMode.Left | ExtendedPlacementMode.Bottom:
                        AssociatedObject.Placement = PlacementMode.Left;
                        offset = GetOffset(AssociatedObject, GetBottomOffset);
                        offset.X -= IndentFromTarget;
                        offset.Y += IndentFromTarget;
                        break;
                    case ExtendedPlacementMode.Right | ExtendedPlacementMode.Top:
                        AssociatedObject.Placement = PlacementMode.Right;
                        offset = GetOffset(AssociatedObject, GetTopOffset);
                        offset.X += IndentFromTarget;
                        offset.Y -= IndentFromTarget;
                        break;
                    case ExtendedPlacementMode.Right | ExtendedPlacementMode.Bottom:
                        AssociatedObject.Placement = PlacementMode.Right;
                        offset = GetOffset(AssociatedObject, GetBottomOffset);
                        offset.X += IndentFromTarget;
                        offset.Y += IndentFromTarget;
                        break;
                    case ExtendedPlacementMode.Left:
                        AssociatedObject.Placement = PlacementMode.Left;
                        offset = GetOffset(AssociatedObject, GetHorizontalCenterOffset);
                        offset.X -= IndentFromTarget;
                        break;
                    case ExtendedPlacementMode.Right:
                        AssociatedObject.Placement = PlacementMode.Right;
                        offset = GetOffset(AssociatedObject, GetHorizontalCenterOffset);
                        offset.X += IndentFromTarget;
                        break;
                    case ExtendedPlacementMode.Center:
                        AssociatedObject.Placement = PlacementMode.Center;
                        break;
                    case ExtendedPlacementMode.Top:
                        AssociatedObject.Placement = PlacementMode.Top;
                        offset = GetOffset(AssociatedObject, GetVerticalCenterOffset);
                        offset.Y -= IndentFromTarget;
                        break;
                    case ExtendedPlacementMode.Bottom:
                        AssociatedObject.Placement = PlacementMode.Bottom;
                        offset = GetOffset(AssociatedObject, GetVerticalCenterOffset);
                        offset.Y += IndentFromTarget;
                        break;
                }
    
                AssociatedObject.HorizontalOffset = offset.X;
                AssociatedObject.VerticalOffset = offset.Y;
            }
    
            private static Point GetOffset(Popup popup, Func<FrameworkElement, FrameworkElement, Point> getOffset)
            {
                var target = popup.PlacementTarget as FrameworkElement;
                var child = (popup.Child ?? popup) as FrameworkElement;
    
                if (target != null && child != null)
                {
                    return getOffset(target, child);
                }
    
                return new Point();
            }
    
            private static Point GetHorizontalCenterOffset(FrameworkElement target, FrameworkElement popup)
            {
                var y = (target.ActualHeight - popup.ActualHeight) / 2;
    
                return new Point(0.0, y);
            }
    
            private static Point GetVerticalCenterOffset(FrameworkElement target, FrameworkElement popup)
            {
                var x = (target.ActualWidth - popup.ActualWidth) / 2;
    
                return new Point(x, 0.0);
            }
    
            private static Point GetTopOffset(FrameworkElement target, FrameworkElement popup)
            {
                var y = -popup.ActualHeight;
    
                return new Point(0.0, y);
            }
            
            private static Point GetBottomOffset(FrameworkElement target, FrameworkElement popup)
            {
                var y = target.ActualHeight;
    
                return new Point(0.0, y);
            }
        }
    
        [Flags]
        public enum ExtendedPlacementMode
        {
            Default = 0,
            Left = 1,
            Right = 2,
            Top = 4,
            Bottom = 8,
            Center = 16
        }
    }
    
    <UserControl
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:beh="clr-namespace:YourNameSpace;assembly=YourAssembly">
    
        <Popup>
            <i:Interaction.Behaviors>
                <beh:PopupExtendedPlacementBehavior Placement="Bottom,Right" IndentFromTarget="4"/>
            </i:Interaction.Behaviors>
        </Popup>
    </UserControl>
    

    【讨论】:

    • 哇!没想到这么快就给出了这么全面的答案。对此,我真的非常感激。我将尝试将其与我当前的代码集成,如果我有任何问题,请告诉您。再次感谢。
    • 我刚试过这个,但它似乎没有达到我想要的效果。例如,如果我使用这个: 弹出窗口将显示在网格视图单元格下方一点,但是弹出窗口的宽度仍然是单元格的宽度。相反,我希望它显示它的位置,但让它延伸到屏幕的右侧,以便所有信息都可以看到。
    • 您还可以使用弹出窗口大小进行操作。有可能从点获取屏幕(请参阅stackoverflow.com/questions/1927540/…)并根据需要重新计算大小。
    • 谢谢,我去看看。感谢您的反馈。
    猜你喜欢
    • 2011-10-18
    • 1970-01-01
    • 1970-01-01
    • 2018-08-24
    • 2015-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多