Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#在运行时重写方法_C#_Methods_Runtime_Overriding - Fatal编程技术网

C#在运行时重写方法

C#在运行时重写方法,c#,methods,runtime,overriding,C#,Methods,Runtime,Overriding,我有两个问题 1) 我发现了一个小宝石的代码 太好了。但是它重写了WndProc方法,所以要使用它,我必须在设计时撕掉掉表单上的FlowLayoutPanel子类FlowLayoutPanel,然后最终实例化我的新类并手动创建所有属性,并将对控件的所有引用更改为this.Controls[“ControlName”]。(或者我想我可以创建一个类级别的变量,它本质上就是控件最初的样子,但是当它没有在任何地方声明时,它们如何允许您对它使用intellisense?) 所以现在我只是想知道是否真的有一

我有两个问题

1) 我发现了一个小宝石的代码

太好了。但是它重写了WndProc方法,所以要使用它,我必须在设计时撕掉掉表单上的FlowLayoutPanel子类FlowLayoutPanel,然后最终实例化我的新类并手动创建所有属性,并将对控件的所有引用更改为this.Controls[“ControlName”]。(或者我想我可以创建一个类级别的变量,它本质上就是控件最初的样子,但是当它没有在任何地方声明时,它们如何允许您对它使用intellisense?)

所以现在我只是想知道是否真的有一种运行时的方法来实现它

我可以做一些简单的事情吗,其中MainPanel是控件的名称:

MainPanel = (SmoothScrollingFlowLayoutPanel)MainPanel
SmoothScrollIntercept intercept = new SmoothScrollIntercept(myControl.Handle);

// myControl is now using smooth scrolling, without inheriting from the control
不会那么容易吧?尽管如此,这还是很烦人,因为我仍然需要子类(这可能是一个很好的设计决策,但我希望有一次性的自由)。因此,是否可以将代码放入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是一个事件而不是一个方法,我将如何做同样的事情存储一个事件的原始处理程序列表的副本,首先安装我自己的事件处理程序以运行,然后调用所有原始的事件处理程序

美味小吃

如果有人感兴趣,我注意到平滑滚动代码中可能存在优化:

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

由于我们希望将最后16位从5位转换为4位,因此我们可以将最后一位(XOR)翻转,而不是先“和”再“或”。

不,您所要求的是不可能的。您必须像以前一样创建子类

即使这是一个事件,你也不能做你所追求的。事件的公共界面仅公开
添加
删除
;无法获取或分配附加到事件的实际委托

然而,从另一个角度来看问题,您可能能够利用接口来完成您所寻找的最终结果

编辑


再次查看代码后,
IMessageFilter
将无法工作,因为您无法在
PreFilterMessage
中修改消息;您只能检查或抑制它。在这一点上,最好的办法是覆盖父级
表单中的
WndProc
,并尝试在那里进行操作。您的问题似乎没有通用的解决方案。

如果我正确理解您的问题,您所要做的就是在运行时重写
WndProc
。如果是这样,你所需要的只是一点Win32魔法

每个控件都有一个“句柄”,用于标识它,以便操作系统可以向它发送消息。此句柄通过每个控件上的
handle
属性公开。基本的Win32系统实际上允许您监听任何控件的
WndProc
,只要您有它的句柄。这意味着您不必从Winforms控件继承来修改其Win32行为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);
    } 
}
然后在代码隐藏中,将截取连接到控件:

MainPanel = (SmoothScrollingFlowLayoutPanel)MainPanel
SmoothScrollIntercept intercept = new SmoothScrollIntercept(myControl.Handle);

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

谢谢你,扎克,但我已经完成了让我的窗口平滑滚动。我只是讨厌我必须从设计器中删除控件并动态执行所有操作。@emtucifer:没问题,我只是想让您知道,您不必从
FlowLayoutPanel
继承来覆盖它的
WndProc
。哦,现在我明白了。谢谢我承认我没有读得像我应该读的那样仔细。这是有用的!事实上,你是100%正确的,这是我一直在寻找的答案。(拍了拍额头)谢谢。我知道一点javascript,在那里你可以用方法来实现这一点,所以我只是好奇。现在我想到了,我可以继承FlowLayoutPanel和UserControl吗?这样我的新SmoothScrollingFlowLayoutPanel就可以在设计时放到表单上了?@Emtucifor:不,没有一种.NET语言允许多重继承。但是,您可以从
FlowLayoutPanel
继承并将控件放入工具箱中。如果控件在您的项目中,它应该自动显示在那里。如果它在另一个项目中,您必须右键单击工具箱,单击“选择项…”,然后浏览到该.dll并以这种方式添加控件。这很有帮助。我知道子类UserControls会显示在工具箱中,但不知何故,我忽略了子类常规控件也会出现在工具箱中。谢谢