2010-08-14 6 views
5

У меня есть два вопроса.Метод переопределения C# в Runtime

1) Я нашел небольшой драгоценный камень кода для how to make a control scroll smoothly.

Отлично. Но он переопределяет метод WndProc, поэтому для его использования мне пришлось вырвать FlowLayoutPanel, который я сбросил на форму во время разработки, подкласс FlowLayoutPanel, а затем, наконец, создаст экземпляр нового класса и создаст все свойства вручную и изменим все ссылки для элемента управления this.Controls ["ControlName"]. (Или, я думаю, я мог бы сделать переменную уровня класса, которая по сути является тем, что первоначально был элементом управления, но как они позволяют вам использовать intellisense на нем, когда он не объявлен нигде?)

Так что теперь мне просто интересно, на самом деле это был способ выполнения.

Могу ли я сделать что-то простое, как это, где MainPanel это имя элемента управления:

MainPanel = (SmoothScrollingFlowLayoutPanel)MainPanel 

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

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); 
    } 

Я понимаю, что это, вероятно, довольно наивно. Я рассматриваю метод WndProc как событие, и это не так.

2) Итак мой второй вопрос, если WndProc было события вместо метода, как бы я сделать то же самое, сохранить копию исходного списка обработчиков для события, установить свое собственное событие обработчик для запуска сначала, а затем вызвать все исходные обработчики событий?

ВКУСНОГО BITS

В случае, если кто заинтересован я заметил оптимизацию возможной в гладкой коде прокрутки:

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

Поскольку мы хотим превратить последние 16 бит от 5 до 4, мы может просто перевернуть последний бит (XOR), а не AND, а затем OR.

ответ

8

Если я правильно понял ваш вопрос, все, что вы хотите сделать, это переопределить WndProc во время выполнения. Если это так, все, что вам нужно, это немного магии Win32.

Каждый элемент управления имеет «дескриптор», который идентифицирует его, чтобы операционная система могла отправлять ему сообщения. Эта ручка экспонируется через свойство Handle на каждом элементе управления. Основная система Win32 фактически позволяет вам прослушивать WndProc любого элемента управления, если у вас есть его ручка. Это означает, что вам не нужно наследовать элемент управления Winforms для изменения поведения Win32. System.Windows.Forms.NativeWindow в .NET обертывает эту базовую функциональность.

Вот пример того, как можно достичь этого:

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); 
    } 
} 

Затем в коде позади, прикрепить перехватывать к управлению:

SmoothScrollIntercept intercept = new SmoothScrollIntercept(myControl.Handle); 

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

Спасибо, Зак, но я уже сделал, чтобы мои окна прокручивались плавно. Я просто ненавидел, как мне пришлось вырвать контроль над дизайнером и сделать все динамично. – ErikE

+0

@Emtucifor: Нет проблем, я просто хотел сообщить вам, что вам не нужно наследовать от 'FlowLayoutPanel', чтобы переопределить его' WndProc'. –

+0

О, теперь я понял. Благодарю. Признаюсь, я не читал так тщательно, как должен. Это полезно! На самом деле, вы на 100% прав, это ответ, который я искал. (ударяет лоб) – ErikE

2

Нет, то, что вы просите, невозможно. Вам придется подкласс, как и раньше.

Даже если бы это было событие, вы не смогли бы выполнить то, что вам нужно. Открытый интерфейс для события предоставляет только add и remove; нет способа получить или назначить фактического делегата (-ов), прикрепленного к событию.

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

Редактировать

После глядя на ваш код еще раз, IMessageFilter не будет работать, так как вы не можете изменить сообщение в PreFilterMessage; вы можете только изучить или подавить его.Лучше всего на этом этапе переопределить WndProc в родительском Form и попытаться сделать свои манипуляции там. Не похоже, что есть общее решение вашей проблемы.

+0

Спасибо. Я знаю немного javascript, где вы можете делать это с помощью методов, поэтому мне было просто любопытно. Теперь мне кажется, могу ли я наследовать как FlowLayoutPanel, так и UserControl, чтобы моя новая SmoothScrollingFlowLayoutPanel стала элементом, который я могу отбросить в форме во время разработки? – ErikE

+0

@Emtucifor: Нет, ни один из языков .NET не допускает множественного наследования. Однако вы можете наследовать «FlowLayoutPanel» и поместить свой элемент управления в панель инструментов. Если элемент управления находится в вашем проекте, он должен появиться там автоматически. Если это в другом проекте, вам нужно щелкнуть правой кнопкой мыши на панели инструментов, нажмите «Выбрать элементы ...», затем перейдите к этой .dll и добавьте элемент управления таким образом. –

+0

Это было полезно. Я знал, что подклассы UserControls будут отображаться в панели инструментов, но как-то не хватало, что там тоже появятся подклассы регулярных элементов управления. Благодарю. – ErikE

Смежные вопросы