2010-08-14 14 views
5

Mam dwa pytania.Metoda C# Override w Runtime

1) Znalazłem mały klejnot kodu dla how to make a control scroll smoothly.

Świetnie. Ale to nadpisuje metodę WndProc, więc aby z niej skorzystać, musiałem wyrwać FlowLayoutPanel, który upuściłem na formularzu w czasie projektowania, podklasę FlowLayoutPanel, a następnie w końcu utworzyć moją nową klasę i ręcznie utworzyć wszystkie właściwości i zmienić wszystkie odwołania do kontroli, aby to było. Controls ["ControlName"]. (Chyba mógłbym stworzyć zmienną na poziomie klasy, która jest zasadniczo tym, co pierwotnie było formantem, ale jak pozwalają na użycie intellisense, gdy nie jest nigdzie zadeklarowana?)

Więc teraz zastanawiam się, czy istniał sposób, aby to zrobić.

Czy mogę zrobić coś prostego, jak ten, gdzie MainPanel to nazwa kontrolą:

MainPanel = (SmoothScrollingFlowLayoutPanel)MainPanel 

To nie może być takie proste, prawda? Mimo to, jest to denerwujące, ponieważ wciąż muszę mieć podklasę (co może być dobrą decyzją projektową, ale chciałbym mieć możliwość jednorazowego wykorzystania). Więc byłoby to możliwe, aby umieścić kod do rodzica coś FlowLayoutPanel tak:

private Delegate void WndProcHandler(ref Message m); 
private WndProcHandler w; 

public void SomeCode() { 
    w = MainPanel.WndProc; // get reference to existing wndproc method 
    MainPanel.WndProc = WndProcSmoothScroll; //replace with new method 
} 

private void WndProcSmoothScroll(ref Message m) { // make smooth scrolling work 
    if (
     (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL) 
     && (((int)m.WParam & 0xFFFF) == 5) 
    ) { 
     m.WParam = (IntPtr)(((int)m.WParam & ~0xFFFF) | 4); 
    } 
    if (w != null) { w(); } 
    base.WndProc(ref m); 
    } 

Zdaję sobie sprawę, jest to chyba dość naiwny. Traktuję metodę WndProc tak, jak to jest wydarzenie, a nie jest.

2) Więc moje drugie pytanie brzmi: jeśli WndProc byłby wydarzenie zamiast metody, jak zrobiłbym to samo - przechowywać kopię oryginalnej listy procedur obsługi zdarzeń, zainstalować własne wydarzenie obsługi do uruchomienia, a następnie wywołanie wszystkich oryginalnych procedur obsługi zdarzeń?

TASTY BITS

W przypadku gdy ktoś jest zainteresowany zauważyłem optymalizację możliwe w gładkiej kodu przewijania:

//m.WParam = (IntPtr)(((int)m.WParam & ~0xFFFF) | 4); 
m.WParam = (IntPtr)((int)m.WParam^1); 

Ponieważ chcemy, aby włączyć ostatnie 16 bity od 5 do 4, my można po prostu odwrócić ostatni bit (XOR) zamiast AND, a następnie LUB.

Odpowiedz

8

Jeśli dobrze rozumiem swoje pytanie, wszystko, co chcesz zrobić, to zastąpić WndProc w czasie wykonywania. Jeśli tak, wszystko czego potrzebujesz to odrobina magii Win32.

Każdy element sterujący ma "uchwyt", który identyfikuje go, aby system operacyjny mógł wysyłać do niego wiadomości. Ten uchwyt jest odsłonięty przez właściwość Handle na każdej kontrolce. Podstawowy system Win32 faktycznie pozwala na słuchanie dowolnej kontrolki WndProc, o ile masz jej uchwyt. Oznacza to, że nie musisz dziedziczyć z formantu WinForm, aby zmodyfikować zachowanie Win32. System.Windows.Forms.NativeWindow w .NET zawija tę podstawową funkcjonalność.

Oto przykład, w jaki sposób można to osiągnąć:

class SmoothScrollIntercept : System.Windows.Forms.NativeWindow 
{ 
    public SmoothScrollIntercept(IntPtr hWnd) 
    { 
     // assign the handle and listen to this control's WndProc 
     this.AssignHandle(hWnd); 
    } 

    protected override void WndProc(ref Message m) 
    { 
     // listen to WndProc here, do things 

     if ((m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL) 
      && (((int)m.WParam & 0xFFFF) == 5)) 
     { 
      m.WParam = (IntPtr)(((int)m.WParam & ~0xFFFF) | 4); 
     } 

     base.WndProc(ref m); 
    } 
} 

Następnie w kodzie za przymocować do sterowania osią:

SmoothScrollIntercept intercept = new SmoothScrollIntercept(myControl.Handle); 

// myControl is now using smooth scrolling, without inheriting from the control 
+0

Dziękuję Zach, ale już osiągnąłem sprawne przewijanie okien. Po prostu nienawidziłem tego, jak musiałem oderwać kontrolę od projektanta i robić wszystko dynamicznie. – ErikE

+0

@Emtucifor: Nie ma problemu, chciałem tylko poinformować, że nie musicie dziedziczyć po 'FlowLayoutPanel', aby nadpisać jego' WndProc'. –

+0

Och, teraz rozumiem. Dzięki. Przyznaję, że nie czytałem tak uważnie, jak powinienem. Jest to przydatne! W rzeczywistości masz 100% racji, to jest odpowiedź, której szukałem. (uderza czołem) – ErikE

2

Nie, to, o co prosisz, jest niemożliwe. Będziesz musiał podklasę, jak wcześniej.

Nawet gdyby to było wydarzenie, nie byłbyś w stanie zrobić tego, o co prosisz. Publiczny interfejs zdarzenia wyświetla tylko add i remove; nie ma możliwości uzyskania lub przypisania faktycznych delegatów dołączonych do wydarzenia.

Jednak patrząc na problem ze innym perspektywy, może być w stanie skorzystać z interfejsu IMessageFilter w celu osiągnięcia do końca doprowadzić szukasz.

Edit

Po pobycie w kodzie znowu IMessageFilter nie będzie działać, ponieważ nie można zmodyfikować wiadomość w ciągu PreFilterMessage; możesz go tylko zbadać lub stłumić.W tym momencie najlepiej jest zastąpić WndProc w rodzica Form i spróbować wprowadzić tam swoje manipulacje. Nie wygląda na to, że istnieje ogólne rozwiązanie twojego problemu.

+0

Dzięki. Znam trochę javascriptu, gdzie można to zrobić metodami, więc byłem po prostu ciekawy. Teraz mi się wydaje, czy mogę dziedziczyć zarówno FlowLayoutPanel, jak i UserControl, aby mój nowy SmoothScrollingFlowLayoutPanel stał się elementem, który mogę upuścić w formularzu w czasie projektowania? – ErikE

+0

@Emtucifor: Nie, żaden z języków .NET nie pozwala na dziedziczenie wielokrotne. Możesz jednak dziedziczyć po 'FlowLayoutPanel' i umieścić kontrolę w przyborniku. Jeśli kontrola znajduje się w projekcie, powinna pojawić się tam automatycznie. Jeśli znajduje się w innym projekcie, musisz kliknąć prawym przyciskiem myszy na przyborniku, kliknąć "Wybierz elementy ...", a następnie przejść do tego pliku .dll i dodać kontrolę w ten sposób. –

+0

To było pomocne. Wiedziałem, że podklasy UserControls pojawią się w zestawie narzędzi, ale w jakiś sposób przegapiłem, że pojawią się tam podklasy regularnych kontroli. Dzięki. – ErikE