Способ контролировать, когда изменяется расположение экрана элемента управления? - PullRequest
7 голосов
/ 15 ноября 2011

С WinForms, есть ли способ оповещения об изменении местоположения элемента управления относительно экрана?

Скажем, у вас есть Форма с кнопкой на ней, и вы хотели бы знать, когда кнопка перемещается из ее текущего местоположения в пикселях на экране. Если кнопка перемещена в другое место в ее родительской форме, вы, очевидно, можете использовать событие LocationChanged, но если форма перемещается пользователем, как вы узнаете, что кнопка визуально переместилась?

В этом упрощенном случае быстрый ответ состоит в том, чтобы отслеживать события FormChanged и SizeChanged формы, но может быть произвольное количество уровней вложенности, поэтому мониторинг этих событий для каждого родителя вверх по цепочке к первичной форме невозможен. Использование таймера для проверки изменения местоположения также выглядит как мошенничество (нехорошо).

Короткая версия: Учитывая только произвольный объект Control, есть ли способ узнать, когда местоположение этого Control изменяется на экране, без знания родительской иерархии элемента управления?

Иллюстрация по заказу:

Illustration

Обратите внимание, что эта концепция "закрепления" является существующей возможностью, но в настоящее время она требует знания родительской формы и поведения дочернего элемента управления; это не проблема, которую я пытаюсь решить. Я хотел бы заключить эту логику отслеживания элемента управления в абстрактную форму, от которой могут наследовать «способные к выводу» формы. Есть ли какая-то магия прокачки сообщений, которую я могу использовать, чтобы узнать, когда элемент управления перемещается на экране, не имея дело со всеми сложными родительскими слежками?

1 Ответ

3 голосов
/ 18 ноября 2011

Я не уверен, почему вы сказали бы, что отслеживание родительской цепочки "неосуществимо".Мало того, что это возможно, это правильный ответ и простой ответ.

Просто быстрый взлом решения:

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