Przechwytywanie zdarzeń z całego okna aplikacji

0

Poszukuję sposobu na przechwytywanie zdarzeń kliknięć myszką z całego okna aplikacji bez względu na to czy odbywa się to na panelu umieszczonym na formie czy na pasku tytułu. Próbowałem przesłonięcia procedury WndProc w Formie okna ale niestety to nie przechwytuje zdarzeń kliknięć na pasku tytułu jak i na kontrolkach i panelach umieszczonych na formie.

0

Do czego jest Ci potrzebne kliknięcie na pasku tytułu?

0

ehh dobra to opisze mój problem troszke inaczej.. właśnie piszę własną kontrolkę autocomplete textbox z dynamicznie ładowanymi podpowiedziami z bazy danych. We frameworku jest wbudowany mechanizm autocomplete, który niestety nie działa (wykrzacza sie w pewnych warunkach). W momencie ładowania podpowiedzi z bazy danych zależnych od aktualnie wpisanego tekstu do listy autocomplete wyskakuje mi error "write to protected memory" (przy czym ładowanie musi trwać pare dobrych milisekund żeby można było wyłapać ten błąd). Listę ładuje w ten spób:

           
            //kod umieszczony jest w zdarzeniu texbox'a - TextChanged
            String strWord = tb_SearchWord.Text;

            autoComplete = (autoComplete != autoComplete1 ? autoComplete1 : autoComplete2);

            if (autoComplete.Count > 0)
            {
                autoComplete.Clear();
            }

            if (strWord.Length >= minTextLenght)
            {
                String[] result = db.getWordStrLikeStartWith(strWord, Count);

                if (result != null)
                    autoComplete.AddRange(result);
            }
            tb_SearchWord.AutoCompleteCustomSource = autoComplete;

Oczywiście jest to tylko jeden z wariantów których juz próbowałem by ominąć ten błąd (w powyższym kodzie korzystam z 2 list AutoCompleteStringCollection, które naprzemian uzupełniam i podczepiam pod customAutoCompleteSource). Podejrzewam że błąd ten jest spowodowany tym że w pewnym momecie jeden z wątków odpowiedzialnych za wyswietlanie listy blokuje do niej dostęp w momencie wykonywanych przeze mnie operacji na tej liście. Próbowałem już wszystkiego co znalazłem na necie i nic ;/, łącznie z zakładaniem własnego locka na kolekcję autocomplete itp... Ze zdarzeniami keyUp i keyDown jest to samo ;/. Być może gdybym robił to na jakieś inne zdarzenie które nie zmienia wartości tekstu w textboxie ten błąd pewnie by nie wyskakiwał, ale niestety nie działałoby to tak jak chcę.

I w końcu przeszedłem do napisania własnej kotrolki autocomplete opartej na ToolStripDropDown, do której za pomocą ToolStripControlHost wrzuciłem kontrolkę ListBox.
Listę podpowiedzi wyświetlam gdy coś wpiszę w textBoxa. W momencie wyświetlania ToolStripDropDown jestem zmuszony ustawiać właściwość AutoClose = false, tak bym miał możliwość wpisywania tekstu w texboxa i jednocześnie obserwowania zmieniających sie podpowiedzi. W odpowiednim momenicie zamykam listę podpowiedzi jednoczesnie ustawiajac AutoClose = true.

Kontolka pięknie śmiga tylko jest jeden szkopół spowodowany właśnie przez ustawienie AutoClose = false w momecie wyswietlania listy. Chciałbym aby lista podpowiedzi chowała sie tak jak to działa we wbudowanej liście autocomplete tzn w momencie nacisniecia przycisku myszy na jakikolwiek inny element okienka Formy. Do tego potrzebuje funkcji obsługi zdarzenia która mi to wyłapie i w której ustawie AutoClose = true.

0

Wrzuciłem funkcje zamykajace i otwierajace liste podpowiedzi.

        public void ShowDropDown(Object[] items)
        {
            ClearDropDown();
            listBox.Items.AddRange(items);
            AdjustSize();
            base.AutoClose = false;
            base.Show(parentControl, -1, parentControl.Height - 2);
           
        }
        public void HideDropDown()
        {
            base.AutoClose = true;
            base.Hide();
            ClearDropDown();
            //AdjustSize();
        }
 
0

A złapanie utraty focus na twojej kontrolce ci nie wystarczy?

0

od samego początkuma problem z focusem. Już na samym początku wyswietlania listy z podpowiedziami kontrolka ToolStripDropDown musi zostac pozbawiona focusu tak bym mógł w tym samym czasie pisać w tekstboxie i dlatego ustawiam AutoClose = false - by lista nie zamknęła się automaczycznie po jego utracie. Próbowałem z oprogramowaniem zdarzenia OnLostFocus w textboxie i w ToolStripDropDown.

 
        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
            // ponizszy warunek sprawia ze lista zamyka mi sie w momencie utraty focusu jednoczesnie przez textbox i kontrolke ToolStripDropDown
            // musze sprawdzac oba focusy bo mam oprogramowane zdarzenia np wybierania odpowiedznich elementow z wyswietlanej listy przy pomocy strzalek  
            // tak że czasem mam focus na textboxie a czasem na wyswietlanej liscie 
            if (!acDropDown.Focused && !base.Focused)
                acDropDown.HideDropDown();
        }

W tym przypadku lista podpowiedzi zamyka mi się gdy jednoczesnie textBox i ToolStripDropDown (a raczej ListBox w niej umieszczony) utracą focus.
Działa to w przypadku gdy klikam ja jakiś przycisk lub innego textboxa, ale nie zadziała w momencie klikania na panel na którym umieszczonym umieszczone jest kontrolka lub na inny element formy który nie powoduje utratu focusu przez mojego textboxa. Chciałbym "jakoś tak ;) ładnie i zgrabnie" rozwiązać ten problem nie podpinajac miliona zdarzen do wystkiego co jet na formie.

0
massther napisał(a)

Zobacz komunikat WM_NCHITTEST
http://msdn.microsoft.com/en-us/library/ms645618.aspx

Właśnie o takie rozwiązanie mi chodzi. Jednak z uwagi na to że piszę własną kontrolkę i chciałbym żeby działała od razu po przeciągnieciu na forme, bez przesłaniania funkcji WndProc w formie. \

0

Jak dokładniej opisałeś problem, to powiem tak: zapomnij o wm_nchittest! Raczej musisz poprawnie przemyśleć swoją kontrolkę. Muszę jeszcze raz przeczytać co i jak dokładnie zrobiłeś żeby ci odpowiedzieć, ale możesz też poszukać na codeproject.com jakiegoś gotowca.

0

kontrolka jest już praktycznie napisana i tylko to mi zostało.. ;/

0

Ja wróciłbym do pomysłu z TextBox i AutoCompleteCustomSource, tylko zastosował trochę inny pomysł niż ty.
Twoja metoda działała synchronicznie i prawdopodobnie dlatego się coś sypało.
Jeśli wprowadzono minimalną liczbę znaków po których pokazywać podpowiedzi (załóżmy dla przykładu 3), to miałbym w aplikacji słownik, który trzyma listę stringów dla takich trzech pierwszych znaków. Jeśli go nie ma, to np. tylko czyści source w TextBox i w osobnym wątku pobiera dane, które mogą się długo pobierać. Jeśli pobierze to uaktualnia source (pamiętaj o modyfikaci kontrolki w wątku głównym - InvokeRequired). Jeśli ktoś dopisze czwartą literkę, to nie trzeba ściągać podpowiedzi z bazy, bo masz już w aplikacji szerszy słownik, wystarczy go tylko zawęzić i podpiąć pod source. Jeśli spodziewasz się dużej liczby danych, to znowu w osobnym wątku. Powstaje pytanie czy liczba podpowiedzi większa niż 100 ma sens, ale to pytanie biznesowe, ciebie jako twórcę uniwersalnej kontrolki to nie obchodzi.
Jeśli ktoś wprowadzi na początku trzy nowe znaki, to trzeba nowy słownik pobrać, pobieranie danych z bazy czy cache'owanych w aplikacji powinno być przezroczyste dla samej kontrolki, łatwiej będzie ten mechanizm modyfikować.
Przy takim podejściu unikniesz jakiś dziwnych czary mary które chcesz zrobić z nchittest, które wcześniej czy później się zemszczą, bo jak się próbuje coś mega pod prąd i niezgodnie ze sztuką zrobić to jest to często źródło bardzo interesujących problemów.

0

już rozwiązałem problem ;)
Na podstawie tego przykładu:
http://support.microsoft.com/kb/318804
Po paru modyfikacjach tej klasy dodałem hook'ka na mouse event przy pomocy funkcji SetWindowsHookEx z parametrem WH_MOUSE = 7 i przefiltrowałem w funkcji zdarzenia na kliknięcie. Wszystko ładnie działa nawet dla paru kontrolek naraz.

1 użytkowników online, w tym zalogowanych: 0, gości: 1