Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Разработка Windows Forms > Событие клика всех компонентов формы?


Автор: skhilkov 2.5.2011, 07:42
Здравствуйте, пытаюсь победить такую вещь: нужно чтобы листбох закрывался при нажатии на любом другом компоненте формы,
ну типа контекстный он. Пытался  отловить Windows Messages, реализовал IMessageFilter в форме. Программа начинает жутко тормозить, просто висит... Пробовал назначить обработчик события всем элементам формы после ее инициализации(рекурсивно) - не работает для некоторых компонентов, непонятно почему... Может я неправильно как-то реализовал IMessageFilter, нужно как-то особенно это делать?
Вот что я пробовал:
Код

Application.AddMessageFilter(filter);
...
 class MessageFilter : IMessageFilter
    {
        private static int WM_LBUTTONDOWN = 0x0201;
        private static int WM_RBUTTONDOWN = 0x0204;
        private MainForm mainForm;

        public MainForm MainForm
        {
            get { return mainForm; }
            set { mainForm = value; }
        }


        public bool PreFilterMessage(ref Message m)
        {
            //handle button click 
            if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_RBUTTONDOWN)
            {
                //if not over datagrid column header checked listbox, close it
                Point p = new Point((int)m.LParam);
                if (mainForm != null)
                {
                    mainForm.handleMouseClickWindowsEvent(p);
                }
            }

            return true;
        }
    }


А это второй способ:
Код

public MainForm()
        {
            InitializeComponent();            
            hookControl(this);
        }

        private void hookControl(Control current)
        {
            foreach (Control cur in current.Controls)
            {
                cur.MouseClick += new MouseEventHandler(MainForm_MouseClick);
                hookControl(cur);
            }
        }

Автор: Rohoss 2.5.2011, 14:57
skhilkov, а почему не использовать событие LostFocus ?

Автор: skhilkov 3.5.2011, 05:13
Rohoss
это несколько неудобно... во-первых, компонент появляется по нажатию на кнопку, то есть он сам появляется не в фокусе,
во-вторых, неудобно для пользователя если он мышь нечаянно отвел  на пиксель в сторону..
В общем есть аналогичная реализация на Дельфи, надо сделать также )

Автор: Rohoss 3.5.2011, 06:08
Цитата(skhilkov @  3.5.2011,  05:13 Найти цитируемый пост)
Rohoss, 
это несколько неудобно... во-первых, компонент появляется по нажатию на кнопку, то есть он сам появляется не в фокусе,
во-вторых, неудобно для пользователя если он мышь нечаянно отвел  на пиксель в сторону..
В общем есть аналогичная реализация на Дельфи, надо сделать также ) 

Тебе нужно впхнуть листбокс в меню? А возможности WPF использовать нет? Так как там всё это прекрасно реализуется...

Автор: -Mikle- 3.5.2011, 07:15
Цитата(Rohoss @  2.5.2011,  17:57 Найти цитируемый пост)
skhilkov, а почему не использовать событие LostFocus ? 

Цитата(skhilkov @  3.5.2011,  08:13 Найти цитируемый пост)
это несколько неудобно... во-первых, компонент появляется по нажатию на кнопку, то есть он сам появляется не в фокусе,
во-вторых, неудобно для пользователя если он мышь нечаянно отвел  на пиксель в сторону..

Не правда. Если сделать MouseCapture, то все нормально. Он для этого и нужен, чтобы зафиксировать на время все события мыши на одном контроле. ComboBox и Menu как работает? Именно так. На выпадающем окне вызывается MouseCapture. На нем висит обработчик клика. Если координаты клика находятся за пределами (минусовые или больше размеров списка), то спокойно закрываешь свой бокс. То что на делфи сделано так же, то это не показатель для C#. Надо делать всегда по человечески и не извращаться. А вообще Rohoss прав, надо на WPF уже переходить. Недельки две позанимаешься и будешь счастлив рисуя интерфейсы.

Автор: skhilkov 3.5.2011, 13:32
Цитата

Если сделать MouseCapture

Это, как я понимаю уже WPF? Больше я не нашел класса Mouse нигде..

Цитата

То что на делфи сделано так же, то это не показатель для C#. Надо делать всегда по человечески и не извращаться.

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

То есть, как я понял без WPF эту задачу не решить??

Автор: -Mikle- 3.5.2011, 18:40
Вообще, лучше найди какой-нибудь PopupControl в инете. Думаю их много. А чтоб поиграться с Capture, вот тебе простой класик:
Код

    public class PopupBehavior
    {
        public PopupBehavior(Control content)
        {
            Content = content;
            Content.Visible = false;
        }

        public Control Content { get; private set; }

        public void Show()
        {
            Content.MouseDown += content_MouseDown;
            Content.Visible = true;
            Content.Capture = true;
        }
        public void Close()
        {
            Content.Capture = false;
            Content.Visible = false;
            Content.MouseDown -= content_MouseDown;
        }

        private void content_MouseDown(object sender, MouseEventArgs e)
        {
            if (!Content.ClientRectangle.Contains(e.Location))
            {
                this.Close(); // Кликнул не в меня
            }
            else
            {
                MessageBox.Show("попал в меня");
                Content.Capture = true;
            }
        }
    }


Используешь так:
Код

    public partial class Form1 : Form
    {
        PopupBehavior listBoxLikePopup;

        public Form1()
        {
            InitializeComponent();
            listBoxLikePopup = new PopupBehavior(listBox1);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listBoxLikePopup.Show();
        }
    }


Но лучше все таки WPF, рано или поздно все равно ПРИДЕТСЯ.

Автор: skhilkov 4.5.2011, 06:30
-Mikle-
Респект тебе и уважуха, это то, что мне было нужно!
Теперь чтобы до конца усвоить пройденный материал - Content.Capture = true; в данном случае означает 
для контрола перехватывать события мыши(или не только)? Так?

Автор: -Mikle- 5.5.2011, 06:20
Не за что.

http://msdn.microsoft.com/ru-ru/library/system.windows.forms.control.capture.aspx#Y260
Цитата

Возвращает или задает значение, определяющее, была ли мышь захвачена элементом управления

Автор: skhilkov 8.5.2011, 19:47
-Mikle-
привет еще раз )
Слушай, такой вопрос - в твоем примере если из кода обработки щелчка убрать кусок
Код

MessageBox.Show("попал в меня");

То все перестает работать ((
Почему так???

Автор: -Mikle- 9.5.2011, 10:07
мдаа... странно... не знаю я...
Вообще капче сбрасывается автоматом всегда, поэтому его состояние надо восстанавливать каждый раз. Возможно, оно сбрасывается во время первого Idle приложения и поэтому его установка после мессадж бокса дает эффект, а без него нет. Надо подумать или почитать, как с ним работать. Щас не охота пока, может завтра.

Автор: skhilkov 12.5.2011, 12:37
Все становится более интересно )
Ситуация вырисовывается... Значит если кликнуть на кнопку "Показать", появляется листбокс, если кликнуть мимо - исчезает, НО если в нем чекнуть какой-нибудь Item, то больше он  не исчезает. Я обработал событие itemCheck вот так: 
Код

filteringListBox.Capture = true;
            if (!filteringListBox.Capture)
            {
                MessageBox.Show("Not captured!");
            }
            else 
            {
                MessageBox.Show("Captured!");
            }

После чека вылазит окно окно с надписью "Captured!"!!! Но при этом если кликнуть мимо, обработка mouseDown листбокса не вызывается!!!
Как такое бывает?

Роюсь дальше..

Автор: -Mikle- 12.5.2011, 13:21
Кажется еще есть событие LostCapture, может попробовать его задействовать? Или поискать комбобокс с открытым исходником и посмотреть как там. Здача должна решаться, по идее, очень просто и тривиально. Просто где-то что-то упущено еще в коде.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)