c# - WPF - 将控件从左边缘扩展到窗口边缘
问题描述
我目前正在使用 Popup 控件作为工具提示的屏幕 (C#/WPF) 以提供附加功能(例如复制和粘贴数据)。当单元格悬停在网格视图中时,弹出窗口会显示。我想要完成的是在单元格正下方显示弹出窗口,并允许它向右扩展但不超过屏幕边缘。
到目前为止,我已经能够让它显示在单元格下方并成为单元格的确切宽度。但是,我无法让它扩展到屏幕右侧。我所有的尝试要么没有结果,要么弹出窗口扩大了屏幕的整个宽度。
我一直在尝试将这些SystemParameters
属性与element.PointToScreen(new Point(0, 0))
没有成功的结合使用。我也尝试过PresentationSource.FromVisual(gridCell)
使用 进行一些操作并获得目标点source.CompositionTarget.TransformFromDevice.Transform()
,但同样没有成功。
显示位于特定点并扩展(向右)到屏幕边缘的 Popup 控件的最简单方法是什么?TIA
解决方案
我想,你所需要的 - 弹出位置校正。您可以定义自定义行为。我解决了类似的问题,想和你分享我的代码。我相信你可以改变它以获得必要的行为。
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>
推荐阅读
- java - Java - 创建游戏。套件、关联球员和球员套件字段
- django - order_by 基于条件
- javafx - 如何访问 Java 模块系统中的私有/包保护字段和方法?
- pytorch - 在 PyTorch 中做 ReLU1
- laravel - 只有管理员角色才能访问 /admin。但它不工作
- r - dplyr::complete/fill 时间序列,但仅限于有限的时间段
- ios - Flutter iOS - 运行脚本:xcode_backend.sh 不允许操作
- python - 通过数组中的特定值求和
- java - 如何从流中仅提取一个允许的元素?
- elasticsearch - 如何仅在elasticsearch中的嵌套对象数组中搜索最近插入的对象(通过日期字段知道)