C# 控件';屏幕位置的改变?

C# 控件';屏幕位置的改变?,c#,winforms,controls,location,screen,C#,Winforms,Controls,Location,Screen,对于WinForms,是否有一种方法可以在控件相对于屏幕的位置发生变化时发出警报 假设您有一个带有按钮的窗体,并且希望知道按钮何时从屏幕上的当前像素位置移动。如果按钮被移动到其父窗体上的其他位置,您显然可以使用LocationChanged事件,但是如果该窗体是由用户移动的,您如何知道按钮已在视觉上移动 在这种简化的情况下,快速的解决方法是监视窗体的LocationChanged和SizeChanged事件,但是嵌套的级别可以是任意的,因此监视主窗体链上每个父级的事件是不可行的。使用计时器检查位

对于WinForms,是否有一种方法可以在控件相对于屏幕的位置发生变化时发出警报

假设您有一个带有按钮的窗体,并且希望知道按钮何时从屏幕上的当前像素位置移动。如果按钮被移动到其父窗体上的其他位置,您显然可以使用LocationChanged事件,但是如果该窗体是由用户移动的,您如何知道按钮已在视觉上移动

在这种简化的情况下,快速的解决方法是监视窗体的LocationChanged和SizeChanged事件,但是嵌套的级别可以是任意的,因此监视主窗体链上每个父级的事件是不可行的。使用计时器检查位置是否改变似乎也像作弊(以一种不好的方式)

短版: 如果只给定一个任意控件对象,是否有办法在不知道控件的父层次结构的情况下知道该控件在屏幕上的位置何时更改

根据要求提供的说明:


请注意,此“固定”概念是一个现有功能,但它当前需要了解父窗体以及子控件的行为方式;这不是我想要解决的问题。我想将这个控件跟踪逻辑封装在一个抽象形式中,“pin-able”形式可以从中继承。我是否可以利用一些信息泵魔法来了解控件何时在屏幕上移动,而不必处理所有复杂的父链跟踪?

我不知道为什么你会说跟踪父链“不可行”。这不仅是可行的,而且是正确和简单的答案

只需快速破解一个解决方案:

private Control         _anchorControl;
private List<Control>   _parentChain = new List<Control>();
private void BuildChain()
{
    foreach(var item in _parentChain)
    {
        item.LocationChanged -= ControlLocationChanged;
        item.ParentChanged -= ControlParentChanged;
    }

    var current = _anchorControl;

    while( current != null )
    {
        _parentChain.Add(current);
        current = current.Parent;
    }

    foreach(var item in _parentChain)
    {
        item.LocationChanged += ControlLocationChanged;
        item.ParentChanged += ControlParentChanged;
    }
}

void ControlParentChanged(object sender, EventArgs e)
{
    BuildChain();
    ControlLocationChanged(sender, e);
}

void ControlLocationChanged(object sender, EventArgs e)
{
    // Update Location of Form
    if( _anchorControl.Parent != null )
    {
        var screenLoc = _anchorControl.Parent.PointToScreen(_anchorControl.Location);
        UpdateFormLocation(screenLoc);
    }
}
private Control\u anchorControl;
私有列表_parentChain=新列表();
私有void BuildChain()
{
foreach(父链中的变量项)
{
item.LocationChanged-=控制位置已更改;
item.ParentChanged-=ControlParentChanged;
}
无功电流=_锚定控制;
while(当前!=null)
{
_parentChain.Add(当前);
current=current.Parent;
}
foreach(父链中的变量项)
{
item.LocationChanged+=控制位置已更改;
item.ParentChanged+=ControlParentChanged;
}
}
void ControlParentChanged(对象发送方,事件参数e)
{
BuildChain();
ControlLocationChanged(发送方,e);
}
void ControlLocationChanged(对象发送方,事件参数e)
{
//更新表格的位置
如果(_anchorControl.Parent!=null)
{
var screenLoc=_anchorControl.Parent.PointToScreen(_anchorControl.Location);
更新格式位置(screenLoc);
}
}

为什么不能一直监控到顶部窗口的所有父代呢?假设您有20层嵌套,全部停靠以填充。当您通过拖动边框来调整主窗体的大小时,SizeChanged事件将在每个级别上触发,在拖动过程中会多次触发。那是一大堆多余的活动。其次,这些控件可能会从一个位置移动到另一个位置(完全不同的嵌套层次结构),因此,即使您为每个父级连接ParentChanged,在更改后,如果不在遍历时存储所有父级控件信息,您也无法从以前的父级中取消挂钩SizeChanged/LocationChanged。这一切看起来都很肮脏。这似乎是一个需要问的问题:“你想做什么?”我想将一个表单“固定”到任意控件上,因此当控件移动时,表单的位置将保持在与控件相对的同一位置。也许您可以提供一些您试图完成的操作的屏幕截图。这是我在对该问题的大量评论中回避的可能解决方案,但我觉得它很脏。不过,我觉得没有更好的办法。