运行时的C#覆盖方法

时间:2010-08-14 02:02:41

标签: c# methods runtime override

我有两个问题。

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 事件而不是方法,我将如何做同样的事情 - 为事件存储原始处理程序列表的副本,安装我自己的事件处理程序首先运行,然后调用所有原始事件处理程序?

TASTY BITS

如果有人感兴趣,我注意到平滑滚动代码中可以进行优化:

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

由于我们要将最后16位从5转为4,我们只需翻转最后一位(XOR)而不是AND然后是OR。

2 个答案:

答案 0 :(得分:8)

如果我理解你的问题,你想要做的只是在运行时覆盖WndProc。如果是这样,你只需要一点Win32魔法。

每个控件都有一个“句柄”,用于标识它,以便操作系统可以向其发送消息。此句柄通过每个控件上的Handle属性公开。只要你拥有它的句柄,底层的Win32系统实际上允许你监听任何控件的WndProc。这意味着您不必从Winforms控件继承来修改其Win32行为。 .NET中的System.Windows.Forms.NativeWindow包含了这个底层功能。

以下是如何实现此目标的示例:

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

答案 1 :(得分:2)

不,你所要求的是不可能的。你必须像以前那样继承子类。

即使这是一个事件,你也无法做到你所追求的。事件的公共接口仅公开addremove;无法获得或指定附加到活动的实际代表。

但是,从不同的角度查看问题,您可以使用IMessageFilter界面来完成您正在寻找的最终结果对

修改

再次查看您的代码后,IMessageFilter将无效,因为您无法修改PreFilterMessage内的消息;你只能检查或压制它。此时您最好的选择是覆盖父WndProc中的Form并尝试在那里进行操作。它看起来不像是你的问题的通用解决方案。