Eri*_*ikE 5 c# methods overriding runtime
我有两个问题.
1)我找到了一些关于如何平滑地进行控件滚动的代码.
大.但是它会覆盖WndProc方法,所以要使用它,我必须撕掉我在设计时删除窗体上的FlowLayoutPanel,子类FlowLayoutPanel,然后最终实例化我的新类并手动创建所有属性并更改所有引用控制为this.Controls ["ControlName"].(或者我想我可以创建一个类级变量,它本质上就是控件最初的变量,但是当它没有在任何地方声明时,它们如何让你使用intellisense?)
所以现在我只是想知道实际上是否有运行方式来实现它.
我可以做一些简单的事情,其中MainPanel是控件的名称:
MainPanel = (SmoothScrollingFlowLayoutPanel)MainPanel
Run Code Online (Sandbox Code Playgroud)
它不是那么容易,可以吗?即便如此,它仍然很烦人,因为我仍然必须拥有子类(这可能是一个很好的设计决定,但我想要一次性的自由).那么可以将代码放入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);
}
Run Code Online (Sandbox Code Playgroud)
我意识到这可能很天真.我正在对WndProc方法进行处理,就像它是一个事件,而事实并非如此.
2)那么我的第二个问题是,如果WndProc 是一个事件而不是一个方法,我将如何做同样的事情 - 为事件存储原始处理程序列表的副本,安装我自己的事件处理程序以先运行,然后调用所有原始事件处理程序?
美味的比特
如果有人感兴趣,我注意到平滑滚动代码中可能的优化:
//m.WParam = (IntPtr)(((int)m.WParam & ~0xFFFF) | 4);
m.WParam = (IntPtr)((int)m.WParam ^ 1);
Run Code Online (Sandbox Code Playgroud)
由于我们希望将最后16位从5转为4,我们只需翻转最后一位(XOR)而不是AND然后是OR.
如果我正确理解你的问题,你想要做的只是WndProc在运行时覆盖.如果是这样,你需要的只是一个小小的Win32魔法.
每个控件都有一个"句柄",用于标识它,以便操作系统可以向其发送消息.此句柄通过Handle每个控件的属性公开.WndProc只要你拥有它的句柄,底层的Win32系统实际上允许你监听任何控件.这意味着您不必从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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在后面的代码中,将截距附加到控件:
SmoothScrollIntercept intercept = new SmoothScrollIntercept(myControl.Handle);
// myControl is now using smooth scrolling, without inheriting from the control
Run Code Online (Sandbox Code Playgroud)