当前位置: 首页 > 编程语言 > C#

WindowsForms中泛型事件处理器的解决方案分享

时间:2023-04-11 02:23:55 C#

WindowsForms中泛型事件处理器的解决方案很久以前,我注意到VisualStudio的WindowsForms编辑器不支持包含泛型类型参数事件。例如,像这样的事件publiceventEventHandlerMyStrangeEvent{add{...}remove{...}}}甚至没有出现在事件列表的VisualStudio属性管理器中。现在,这是一个有点做作的示例,可以通过覆盖类及其事件轻松修改以在VisualStudio中工作。但是,我目前正在从事一个项目,由于兼容性原因,我无法更改某些类。我唯一能做的就是更改用户控件的事件。此控件的事件当前如下所示:publiceventEventHandlerDrawingError{add{_Plane.DrawingError+=value;}移除{_Plane.DrawingError-=值;}}_Plane实例,它是一个受保护的字段)。它的DrawingError事件及其EventArgs类型在Plane类中声明如下:publicclassPlanewhereT:ISurface{...publiceventEventHandlerDrawingError=null;...publicclassDrawingErrorEventArgs:EventArgs{.../*UsesT*/...}}当然,VisualStudio的Windows窗体编辑器不会为我的用户控件显示任何事件。我一直在寻找一些解决方法让它们再次出现,但找不到任何实际有效的方法。以下是我尝试过的一些事情:创建了一个继承自Plane的MyPlane类,并使用了这个:publiceventEventHandlerDrawingError...由于我不知道的原因,该事件仍然没有出现在编辑器中。也许这是由于事件的参数,其中一些仍然是通用的。在下面找到一个最小的工作示例。创建了一个辅助类,它定义了EventHandler和EventHandler之间的隐式转换运算符,其中GDIPlane只是一个继承自Plane的虚拟类。这在某种程度上有效,但会重复事件调用,因为转换会创建新的事件处理程序,这些处理程序将传递给无法正确删除/注销的_Plane。试图从EventHandler继承,这显然不起作用,因为EventHandler是密封的。还有其他方法可以在Windows窗体编辑器中再次显示我的事件吗?最好的问候Andreas编辑:1的最小工作示例:publicinterfaceISurface{}publicclassGDISurface:ISurface{}publicclassPlanewhereT:ISurface{publiceventEventHandlerDrawingError=null;publicclassDrawingErrorEventArgs:EventArgs{T东西;}}publicclassTestControl:UserControl{publicclassGDIPlane:Plane{}GDIPlane_Plane=null;公共事件EventHandlerDrawingError{添加{_Plane.DrawingError+=值;}移除{_Plane.DrawingError-=值;}}}单击TestControlinstance,DrawingError不会出现在属性管理器的事件列表中。EDIT2:这是TestControl的DrawingError事件未显示的原始问题(没有任何解决方法):publicclassDrawingErrorEventArgs:EventArgs{T东西;}}publicclassTestControl:UserControl{Plane_Plane=null;公共事件EventHandlerDrawingError{添加{_Plane.DrawingError+=值;}移除{_Plane.DrawingError-=值;这是VisualStudio特定的行为,因为EventHandler没有在其“TEventArgs”上指定协方差(这会施加看似愚蠢的限制),并且该工具没有对您的代码进行足够的自省以输出一个适当的类型(即使你在构造控件时留下了类型数据的痕迹。)所以看起来VS不支持通用事件属性。您可能会考虑在MicrosoftConnect上提交功能请求,我不建议将其作为错误提交,因为他们可能会“按设计”标记它并关闭它。作为一般规则,如果您需要在事件上使用通用类型参数,并且需要对它们进行设计时支持(这是一个不同的实现问题),那么您需要将它们包装在特定于表示的外观中(例如“额外的代码层”)以促进设计时要求”。)就个人而言,我会减少你现在正在玩的泛型类型,这似乎有点矫枉过正,如果你不理解泛型类型中的协变/逆变,它会让你在某个时候陷入困境,比如现在。但是,要解决您的问题:考虑使用可以在非通用属性中传输数据的自定义事件参数类,以及非通用EventHandler事件/属性。了解事件的“类型”将不再使用泛型类型参数,而不是负责使用非泛型事件参数。如果事件参数的“类别”不足,可以添加一个属性来传达事件类型(或数据类型),以便接收代码可以正确解释它(当然假设其他人不知道)。):publicclassDataEventArgs:EventArgs{//publicstringEventTypeOrPurpose{get;放;}公共对象数据{得到;EventArgs{公共T数据{获取;放;}}不幸的是,这也有一个协方差问题,要解决它你真的需要更像这样的东西:publicinterfaceIDataArgs{TData{get;}}publicclassDataEventArgs:EventArgs,IDataArgs{publicDataEventArgs(T数据){_data=数据;}私人T_data;公共T数据{获取{返回_data;即便如此,这些通用版本也无法解决VisualStudio限制,这只是您向我们展示的内容的更合适替代方案。更新:根据要求,这是最基本意义上的“专用外观”的样子。请注意,在这种情况下,用户控件充当外观层,因为它向底层对象模型公开委托。用户控件不能直接访问底层对象模型(从消费者/设计者的角度来看)。请注意,除非您在应用程序的整个生命周期中处理这些用户控件,否则您不必为事件处理程序进行引用跟踪(这样做只是为了确保根据提供的委托删除正确的委托,包装在关闭/调试中,如下所示。)另外值得注意的是,除了验证设计器在放置在表单上时在属性网格中显示DrawingError之外,我没有测试运行此代码。namespaceSampleCase3{publicinterfaceISurface{}publicclassGDISurface:ISurface{}publicclassPlanewhereT:ISurface{publiceventEventHandlerDrawingError;publicclassDrawingErrorEventArgs:EventArgs{T东西;}}publicclassTestControl:UserControl{privatePlane_Plane=newPlane();//需要为我自己的测试进行初始化publicTestControl(){}//我添加这个映射*仅*以便可以正确完成事件处理程序的删除privateDictionary.DrawingErrorEventArgs>>_cleanupMap=newDictionary.DrawingErrorEventArgs>>();公共事件EventHandlerDrawingError{添加{varnonGenericHandler=value;vargenericHandler=(EventHandler.DrawingErrorEventArgs>)delegate(objectsender,Plane.DrawingErrorEventArgse){nonGenericHandler(sender,e);};_Plane.DrawingError+=genericHandler;_cleanupMap[nonGenericHandler]=genericHandler;}移除{varnonGenericHandler=value;vargenericHandler=默认值(EventHandler.DrawingErrorEventArgs>);if(_cleanupMap.TryGetValue(nonGenericHandler,outgenericHandler)){_Plane.DrawingError-=genericHandler;_cleanupMap.Remove(nonGenericHandler);}}}}}为了补充上述内容,这里是非通用事件处理程序现在它看起来像:privatevoidtestControl1_DrawingError(objectsender,EventArgse){if(genericDrawingErrorEventArgs!=null){//TODO:}}请注意,此处的消费者必须知道e的类型才能执行转换。假设转换成功,使用as运算符将绕过祖先检查。像这样的事情和你将要得到的一样接近。是的,我们的大多数标准都很丑陋,但如果您绝对需要在这些组件之上提供设计时支持,并且您不能更改平面(这会更合适),那么这个或接近这个的东西是唯一的可行的解决方案解决方案。HTH以上就是C#学习教程的全部内容:Windows窗体通用事件处理器的解决方法。代表立场,如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: