ToolStripDropDown перехватывает MouseeDown перед базовым элементом управления - PullRequest
0 голосов
/ 18 сентября 2018

Я создал свой собственный элемент управления в стиле ComboBox, где раскрывающаяся часть содержит дерево.Я видел эти решения, использующие обычный ComboBox и перезаписывающие WndProc, но всегда было какое-то странное поведение, несмотря на большое количество кода.Поэтому я решил упростить задачу: просто метка с ToolStripDropDown / ToolStripControlHost, которая открывается, когда на ярлыке нажимает мышь.Отсутствующий треугольник ComboBox не помешает.

Все отлично работает, кроме одной крошечной вещи: как со стандартным ComboBox, я бы хотел, чтобы раскрывающийся список скрывался, когда я снова нажимал на ярлык.Но когда я нажимаю на него, выпадающий список прячется на долю секунды, чтобы появиться снова.Если я щелкаю за пределами метки, раскрывающийся список просто скрывается, как и должно быть.

public class RepoNodeComboBox: Label
{
    RepoTreeView repoTreeView;
    ToolStripControlHost treeViewHost;
    ToolStripDropDown dropDown;
    bool isDropDownOpen;

    public int DropDownHeight;

    public RepoNodeComboBox()
    {
        repoTreeView = new RepoTreeView();
        repoTreeView.BorderStyle = BorderStyle.None;
        repoTreeView.LabelEdit = false;

        treeViewHost = new ToolStripControlHost(repoTreeView);
        treeViewHost.Margin = Padding.Empty;
        treeViewHost.Padding = Padding.Empty;
        treeViewHost.AutoSize = false;

        dropDown = new ToolStripDropDown();
        dropDown.CanOverflow = true;
        dropDown.AutoClose = true;
        dropDown.DropShadowEnabled = true;
        dropDown.Items.Add(treeViewHost);
        dropDown.Closing += dropDownClosing;

        TextAlign = ContentAlignment.MiddleLeft;
        BackColor = SystemColors.Window;
        BorderStyle = BorderStyle.FixedSingle;

        DropDownHeight = 400;
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing) 
        {
            if (dropDown != null) 
            {
                dropDown.Dispose();
                dropDown = null;
            }
        }
        base.Dispose(disposing);
    }

    // when mouse goes down on the label, this is executed first            
    void dropDownClosing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        // just to test if I can get more out of it than with dropdown.Visible
        isDropDownOpen = false; 
    }

    // this is subsidiary to the Closing event of the dropdown
    protected override void OnMouseDown(MouseEventArgs e)
    {
        if (dropDown != null) 
        {
            if (isDropDownOpen)
            {
                dropDown.Hide();
            }
            else
            {
                repoTreeView.Size = new Size(Width, DropDownHeight);
                treeViewHost.Width = Width;
                treeViewHost.Height = DropDownHeight;
                dropDown.Show(this, 0, Height);
                isDropDownOpen = true;
            }
        }

        base.OnMouseDown(e);
    }
}

Насколько я вижу (точки останова), раскрывающийся список сначала перехватывает событие MOUSEDOWN, чтобы закрыть себя.Только после этого мой ярлык проходит через событие MOUSEDOWN, и, поскольку он видит, что раскрывающийся список закрыт, он думает, что ярлык был нажат как первый раз - и снова открывает раскрывающийся список.

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

Есть ли способ убедиться, что открытый раскрывающийся элемент просто закрывается, даже если я нажимаю на метку?

1 Ответ

0 голосов
/ 18 сентября 2018

Попробуйте проверить положение мыши, когда плавающий хост закрывается:

void dropDownClosing(object sender, CancelEventArgs e) {
  isDropDownOpen = this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition));
}

В коде MouseDown убедитесь, что для isDropDownOpen установлено значение false в блоке true:

protected override void OnMouseDown(MouseEventArgs e) {
  if (dropDown != null) {
    if (isDropDownOpen) {
      isDropDownOpen = false;
      dropDown.Hide();
    } else {
      isDropDownOpen = true;
      repoTreeView.Size = new Size(Width, DropDownHeight);
      treeViewHost.Width = Width;
      treeViewHost.Height = DropDownHeight;
      dropDown.Show(this, 0, Height);
    }
  }
  base.OnMouseDown(e);
}
...