Подтвердить что ты не робот

События MouseEnter и MouseLeave из панели и ее дочерние элементы управления

У меня есть Panel, который содержит дочерние элементы управления.

Если я обрабатываю события Panel MouseEnter и MouseLeave, а его дочерние события MouseEnter и MouseLeave, события поднимаются в следующем порядке:

Panel.MouseEnter
Panel.MouseLeave
Child1.MouseEnter
Child1.MouseLeave
Panel.MouseEnter
Panel.MouseLeave

Но мне нужен следующий порядок:

Panel.MouseEnter
Child1.MouseEnter
Child1.MouseLeave
Panel.MouseLeave

Возможно ли это?

4b9b3361

Ответ 1

Если вы не возражаете против создания usercontrol (полученного из панели или другого родительского контейнера, который вы хотите) Переопределите родительский метод OnMouseLeave, чтобы выглядеть следующим образом.

protected override void OnMouseLeave(EventArgs e)
{

    if(this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition)))
         return;
    else
    {
        base.OnMouseLeave(e);
    }
}

Затем сбор событий будет в требуемом порядке.

Ответ 2

Мышь "покидает" панель, когда она входит в дочерний элемент управления, поэтому она запускает событие.

Вы можете добавить что-то в следующих строках в панели MouseLeave обработчик событий:

// Check if really leaving the panel
if (Cursor.Position.X < Location.X ||
    Cursor.Position.Y < Location.Y ||
    Cursor.Position.X > Location.X + Width - 1 ||
    Cursor.Position.Y > Location.Y + Height - 1)
{
    // Do the panel mouse leave code
}

Ответ 3

Решение состоит в том, чтобы отслеживать количество входящих/выходящих. В вашем общем контроле добавьте счетчик:

private int mouseEnterCount = 0;

В обработчике MouseEnter сделайте следующее:

if (++mouseEnterCount == 1)
{
   // do whatever needs to be done when it first enters the control.
}

В обработчике MouseLeave выполните следующее:

if (--mouseEnterCount == 0)
{
   // do whatever needs to be done when it finally leaves the control.
}

и выполните вышеупомянутые обработчики событий MouseEnter и MouseLeave для ВСЕХ дочерних элементов управления, а также для содержащего объекта.

Ответ 4

Ответ Мэтью не будет работать всегда. Особенно, если дочерний элемент управления установлен на край его контейнера, и мышь перемещает элементы управления в этом направлении. Вы никогда не обнаружите событие MouseLeave.

Наилучший подход заключается в создании пользовательского контейнера управления, а затем подключении всех событий дочерних элементов управления MouseEnter и MouseLeave, чтобы вы могли правильно определять, когда и где находится мышь. ТОГДА, если он входит в рамки вашего контейнера, вы можете запустить пользовательское событие MouseEnter и когда оно покинет событие MouseLeave.

Ответ 5

Это может быть не самое элегантное решение, но вы можете установить свойство в родительской панели управления (панель подкласса), которая является значением bool, например "bool selected". Затем, когда MouseEnter для панели срабатывает, установите значение true... затем остановите логику mouseleave от срабатывания, если она не установлена ​​в значение false.

Пример

bool selected;

MouseEnter(..,..)
{
 if (!selected)
   selected = true;
 else
   selected = false;

  if (selected)
   /.. Logic Here ../
}

MouseLeave()
{
  if (selected)
   return;

/.. Logic Here ../
}

В реальности я просто хочу, чтобы событие MouseLeave для ребенка задало параметр.

Example:

Parent:
  bool doLeave;

  MouseLeave(..,..)
  {
    if (doLeave)
    {
     /.. Logic ../
     doLeave = false;
  }

Child:
 MouseLeave(..., ...)
  {
    DerivedPanel parent = this.Parent as DerivedPanel;
    if (parent != null)
      parent.doLeave = true;
  }

Не элегантны, но будут работать.

Ответ 6

Я так считаю. Хороший инструмент для проверки ваших событий приложений WinForms.

Порядок событий Windows.Forms

http://missico.spaces.live.com/blog/cns!7178D2C79BA0A7E3!186.entry

  • Создано с EventSpy, написанным Урсом Эйхманом. (ftp://missico.net/EventSpy.zip)
  • Использование платформы .NET Framework 3.5 и с помощью платформы приложений Visual Basic.

Ответ 7

Это сложная задача, и ее будет сложно надежно запрограммировать. Одна идея состоит в том, чтобы "захватить" 3 входящих события в списке и выполнить желаемый код после завершения списка (имеет 3 желаемых события в списке). Затем, когда вы закончите выполнение какого-либо кода (или, возможно, захватите комбо событий в обратном порядке), вы можете удалить свой список и подготовить его в следующий раз, когда произойдет конкретное комбо-событие. Не идеально, а просто мысль.

Конечно, это не преодолевает проблемы с возможным разрешением и возможные пропущенные события, которые поднял Ганс. Возможно, больше контекста в порядке.

Ответ 8

Проверьте дочерний компонент.

if (panel1.GetChildAtPoint(panel1.PointToClient(Cursor.Position)) == null)
{
    // mouse leave panel and children
}

Ответ 9

Джимми Т. прав. Будут проблемы, если нет (или небольшого) пространства между концом родительского контроля (панель) и Child Control.

Вот как я решаю эту проблему в классе, созданном UserControl:

    public CSStackPanelItem()
    {
        InitializeComponent();

        MouseEnter += new EventHandler(CSStackPanelItem_MouseEnter);

        foreach (Control child in Controls)
        {
            child.MouseEnter += (s, e) => CSStackPanelItem_MouseEnter(s, e);
            child.MouseLeave += (s, e) => OnMouseLeave(e);
        }
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        if (this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition)))
            return; //suppress mouse leave event handling

        if (m_bIsHover)
        {
            m_bIsHover = false;
            Invalidate(); //actually my mouse Enter/Leave event
        }

        base.OnMouseLeave(e);
    }

    void CSStackPanelItem_MouseEnter(object sender, EventArgs e)
    {
        m_bIsHover = true;
        Invalidate(); //actually my mouse Enter/Leave event
    }