WndProc 的替代方案,因为在从组件派生的类中需要?

Posted

技术标签:

【中文标题】WndProc 的替代方案,因为在从组件派生的类中需要?【英文标题】:Alternative to WndProc because needed in Class derived from Component? 【发布时间】:2013-03-13 11:36:21 【问题描述】:

我正在编写一个从 Component 派生的自定义控件。

在此控件中,我需要能够以某种方式获取操作系统消息 WM_DEVICEDCHANGED 以从中创建一些事件。

通常我会直接在应用程序表单中覆盖 WndProc,但此功能直接位于控件中非常重要。

即使控件将始终在窗体上使用,重要的是在从组件派生的控件上接收操作系统消息,因此当将控件放到窗体上时,无需手动为其添加功能 IN表格。

我看到了一些提到 NativeWindow 和其他解决方案的例子,但我无法找到其中的头或尾,所以我希望这里有人可以帮助我。

谢谢...

【问题讨论】:

您需要更具体一些,完全不清楚子类化主机表单是否可以工作或需要创建单独的窗口。记录您想要完成的任务,并至少提及您想要接收的消息。 对不起。我以为我已经写过我想收到 WM_DEVICECHANGED 消息。我想在我的组件中接收消息,而不是在使用组件的表单中接收消息。不在表单上使用 WndProc。 我可能解释得不太好,但基本上我希望能够在我的组件中做 WndProc 在表单类中所做的事情。 【参考方案1】:

我想收到 WM_DEVICECHANGED 消息

好的,这只需要子类化您放置组件的窗体的窗口。任何***窗口都会收到该消息。向您的项目添加一个新类并粘贴如下所示的代码。建造。将新组件从工具箱顶部拖放到表单上。为 DeviceChange 事件添加一个事件处理程序,并添加与您感兴趣的设备更改通知类型相关的任何代码。您还可以将该代码放在 OnDeviceChange() 方法中,以进一步专门化通知并引发更具体的事件。您可以从这里拿走它。

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;

public class DeviceChangeNotifier : Component 
    public delegate void DeviceChangeDelegate(Message msg);
    public event DeviceChangeDelegate DeviceChange;

    public DeviceChangeNotifier() 
        // Add initialization here
    
    public DeviceChangeNotifier(IContainer container) : this() 
        // In case you need automatic disposal
        container.Add(this);
    
    public DeviceChangeNotifier(ContainerControl parentControl) : this() 
        // In case you want to use it without the designer            
        this.ContainerControl = parentControl;
    

    public ContainerControl ContainerControl 
        // References the parent form
        get  return this.parentControl; 
        set  
            this.parentControl = value;
            this.parentControl.HandleCreated += parentControl_HandleCreated;
        
    

    private void parentControl_HandleCreated(object sender, EventArgs e) 
        // Subclass the form when its handle is created
        snooper = new MessageSnooper(this, parentControl.Handle);        
    

    protected void OnDeviceChange(Message msg) 
        // Raise the DeviceChange message
        var handler = DeviceChange;
        if (handler != null) handler(msg);
    

    public override ISite Site 
        // Runs at design time, ensures designer initializes ContainerControl 
        // so we'll have a reference to the parent form without it having to do any work
        set  
            base.Site = value;
            if (value == null) return;
            IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (service == null) return;
            IComponent rootComponent = service.RootComponent;
            this.ContainerControl = rootComponent as ContainerControl;
        
    

    private ContainerControl parentControl;
    private MessageSnooper snooper;
    private const int WM_DESTROY = 0x0002;
    private const int WM_DEVICECHANGE = 0x0219;

    private class MessageSnooper : NativeWindow 
        // Subclasses the parent window
        public MessageSnooper(DeviceChangeNotifier owner, IntPtr handle) 
            this.owner = owner;
            this.AssignHandle(handle);
        
        protected override void WndProc(ref Message m) 
            if (m.Msg == WM_DESTROY) this.ReleaseHandle();
            if (m.Msg == WM_DEVICECHANGE) owner.OnDeviceChange(m);
            base.WndProc(ref m);
        
        private DeviceChangeNotifier owner;
    

【讨论】:

谢谢。这样可行。它当然创建了一个新组件,但我认为我可以在没有帮助的情况下将它集成到我自己的组件中。 :) 或者,您也许可以使用 msgwindow 样式(不记得实际值)沿着 pinvoke 的讨厌之路进入 CreateWindow,这也应该给您一个消息泵......跨度> @JerKimball 谢谢,但我得到了 Hans 的解决方案。唯一有点烦人的是 ContainerControl 显示为公共属性。没有办法解决这个问题? 好的,忘记我的最后一个问题。那些日子我是个僵尸……[Browsable(false)] 是答案当然:)

以上是关于WndProc 的替代方案,因为在从组件派生的类中需要?的主要内容,如果未能解决你的问题,请参考以下文章

引用泛型类型的类属性

SQL SSIS 使用派生列转换来处理空数据.. 替代方案?

用于存储的抽象基类的替代方案

为啥在元类派生自ABCMeta的类中需要使用@abstractmethod?

从基类函数派生的类容器

派生类中具有相同名称但不同签名的函数