Как задать событие щелчка для формы?

#c# #winforms

Вопрос:

У меня есть форма c# (назовем ее основной формой) с рядом пользовательских элементов управления на ней. Я бы хотел иметь основную форму.Метод OnClick() срабатывает в любое время, когда кто-то нажимает на форму, независимо от того, произошел ли щелчок в форме или был ли щелчок на одном из пользовательских элементов управления. Я ищу поведение, аналогичное функции KeyPreview в формах, за исключением щелчков мыши, а не нажатий клавиш.

Ответ №1:

Я рекомендую создать базовую форму для наследования других форм в вашем приложении. Добавьте этот код в свою базовую форму, чтобы создать новое событие под названием GlobalMouseClickEventHandler:

 namespace Temp
{
    public delegate void GlobalMouseClickEventHander(object sender, MouseEventArgs e);

    public partial class TestForm : Form
    {
        [Category("Action")]
        [Description("Fires when any control on the form is clicked.")]
        public event GlobalMouseClickEventHander GlobalMouseClick;

        public TestForm()
        {
            InitializeComponent();
            BindControlMouseClicks(this);
        }

        private void BindControlMouseClicks(Control con)
        {
            con.MouseClick  = delegate(object sender, MouseEventArgs e)
            {
                TriggerMouseClicked(sender, e);
            };
            // bind to controls already added
            foreach (Control i in con.Controls)
            {
                BindControlMouseClicks(i);
            }
            // bind to controls added in the future
            con.ControlAdded  = delegate(object sender, ControlEventArgs e)
            {
                BindControlMouseClicks(e.Control);
            };            
        }

        private void TriggerMouseClicked(object sender, MouseEventArgs e)
        {
            if (GlobalMouseClick != null)
            {
                GlobalMouseClick(sender, e);
            }
        }
    }
}
 

Это решение будет работать не только для элементов управления верхнего уровня, но и для вложенных элементов управления, таких как элементы управления, размещенные внутри панелей.

Комментарии:

1. Огромное спасибо! Простое и элегантное решение. Интересно, почему нет чего-то эквивалентного KeyPreview щелчкам мыши

Ответ №2:

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

 Private Sub Example_ControlAdded(ByVal sender As Object, ByVal e As System.Windows.Forms.ControlEventArgs) Handles Me.ControlAdded

    AddHandler e.Control.MouseClick, AddressOf Example_MouseClick
End Sub

Private Sub Example_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
    MessageBox.Show("Click")
End Sub
 

Комментарии:

1. Это все еще кажется немного странным, но, похоже, это лучший вариант, который у меня есть.

Ответ №3:

Единственный способ, которым мне когда-либо удавалось это сделать, — это обработать событие [c]Click[/c] каждого элемента управления. Я не верю, что событие возникает до того, как управление обработает его.

В WPF есть события предварительного просмотра «туннелирования», которые предоставляют эту функциональность, но это на самом деле не помогает вам в WinForms.

Комментарии:

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

Ответ №4:

Вы можете подключить все события элемента управления, если хотите, а затем отслеживать их таким образом. Я предполагаю, что существует какой-то необычный способ Win32 api для их всех, но в данный момент это выше моего понимания.

     public Form1()
    {
        InitializeComponent();
        HookEvents();
    }

    private void HookEvents() {
        foreach (Control ctl in this.Controls) {
            ctl.MouseClick  = new MouseEventHandler(Form1_MouseClick);
        }
    }  

    void Form1_MouseClick(object sender, MouseEventArgs e)
    {
        LogEvent(sender, "MouseClick");
    }

    // and then this just logs to a multiline textbox you have somwhere on the form
    private void LogEvent(object sender, string msg) {
        this.textBox1.Text = string.Format("{0} {1} ({2}) n {3}",
            DateTime.Now.TimeOfDay.ToString(),
            msg,
            sender.GetType().Name,
            textBox1.Text
            );
    }
 

Результат выглядит примерно так: показаны все события и кто их «отправил» :

 14:51:42.3381985 MouseClick (Form1) 
14:51:40.6194485 MouseClick (RichTextBox) 
14:51:40.0100735 MouseClick (TextBox) 
14:51:39.6194485 MouseClick (Form1) 
14:51:39.2131985 MouseClick (RichTextBox) 
14:51:38.8694485 MouseClick (Button) 
 

ХТ.

Ответ №5:

Поймать щелчок на открытом месте в форме легко, но чтобы получить щелчок, который на самом деле находится на элементе управления, вам потребуется сотрудничество этого элемента управления, чтобы отправить его в форму.

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

Комментарии:

1. Я чувствую, что должно быть более элегантное решение, чем это.

Ответ №6:

Это распространенный паттерн в развитии, называемый паттерном наблюдателя. Существует множество примеров шаблонов наблюдателей, и c# вот 1 пример http://msdn.microsoft.com/en-us/library/ms954621.aspx но хорошенько погуглите вокруг.