C# Windows窗体中通用事件处理程序的变通方法
很久以前,我注意到VisualStudio的Windows窗体编辑器不支持包含泛型类型参数的事件。例如,像这样的事件C# Windows窗体中通用事件处理程序的变通方法,c#,winforms,generics,visual-studio-2013,event-handling,C#,Winforms,Generics,Visual Studio 2013,Event Handling,很久以前,我注意到VisualStudio的Windows窗体编辑器不支持包含泛型类型参数的事件。例如,像这样的事件 public event EventHandler<ListEventArgs<int>> MyStrangeEvent { add { ... } remove { ... } } public事件事件处理程序MyStrangeEvent{add{…}remove{…} 在哪里 公共类ListEventTargets:EventArgs{List a
public event EventHandler<ListEventArgs<int>> MyStrangeEvent { add { ... } remove { ... } }
public事件事件处理程序MyStrangeEvent{add{…}remove{…}
在哪里
公共类ListEventTargets:EventArgs{List args;}
甚至不会显示在Visual Studio的属性管理器的事件列表中。现在,这是一个有点人为的示例,可以通过重写类及其事件轻松地修改它以在VisualStudio中工作。但是,我目前正在进行一个项目,由于兼容性原因,我无法更改某些类。我唯一能做的就是更改用户控件的事件。此控件的事件当前如下所示:
public event EventHandler<Plane<GDISurface>.DrawingErrorEventArgs> DrawingError { add { _Plane.DrawingError += value; } remove { _Plane.DrawingError -= value; } }
public class Plane<T> where T : ISurface
{
...
public event EventHandler<DrawingErrorEventArgs> DrawingError = null;
...
public class DrawingErrorEventArgs : EventArgs { ... /* Uses T */ ... }
}
public interface IDataArgs<out T>
{
T Data { get; }
}
public class DataEventArgs<T> : EventArgs, IDataArgs<T>
{
public DataEventArgs<T>(T data)
{
_data = data;
}
private T _data;
public T Data { get { return _data; } }
}
public event EventHandler drawingerro{add{{u Plane.drawingerro+=value;}remove{{u Plane.drawingerro-=value;}
请注意,不能更改基础平面类(由受保护字段的_Plane实例表示)。其DrawingError事件及其EventArgs类型在Plane类中声明如下:
public event EventHandler<Plane<GDISurface>.DrawingErrorEventArgs> DrawingError { add { _Plane.DrawingError += value; } remove { _Plane.DrawingError -= value; } }
public class Plane<T> where T : ISurface
{
...
public event EventHandler<DrawingErrorEventArgs> DrawingError = null;
...
public class DrawingErrorEventArgs : EventArgs { ... /* Uses T */ ... }
}
public interface IDataArgs<out T>
{
T Data { get; }
}
public class DataEventArgs<T> : EventArgs, IDataArgs<T>
{
public DataEventArgs<T>(T data)
{
_data = data;
}
private T _data;
public T Data { get { return _data; } }
}
公共类平面,其中T:i曲面
{
...
公共事件EventHandler DrawingError=null;
...
公共类DrawingErrorEventArgs:EventArgs{…/*使用T*/…}
}
当然,VisualStudio的Windows窗体编辑器不会显示我的用户控件的任何事件。我一直在寻找一些解决办法,以使他们再次显示,但没有能够找到一个解决办法,实际工作。以下是我尝试过的一些事情:
公共事件事件处理程序DrawingError…
。由于我不知道的原因,这些事件仍然没有出现在编辑器中。这可能是由于事件的参数,其中一些参数仍然是通用的。在下面找到一个简单的工作示例EventHandler
和EventHandler
之间的隐式转换运算符,其中GDIPlane只是一个从Plane
继承的伪类。这在某种程度上确实有效,但会复制事件调用,因为转换会创建新的事件处理程序,这些事件处理程序会传递到无法正确删除/注销的_平面EventHandler
继承,这显然不起作用,因为EventHandler
是密封的public interface ISurface { }
public class GDISurface : ISurface { }
public class Plane<T> where T : ISurface
{
public event EventHandler<DrawingErrorEventArgs> DrawingError = null;
public class DrawingErrorEventArgs : EventArgs { T stuff; }
}
public class TestControl : UserControl
{
public class GDIPlane : Plane<GDISurface> { }
GDIPlane _Plane = null;
public event EventHandler<GDIPlane.DrawingErrorEventArgs> DrawingError { add { _Plane.DrawingError += value; } remove { _Plane.DrawingError -= value; } }
}
公共接口ISurface{}
公共类GDISurface:ISurface{}
公共类平面,其中T:i曲面
{
公共事件EventHandler DrawingError=null;
公共类DrawingErrorEventArgs:EventArgs{T stuff;}
}
公共类TestControl:UserControl
{
公共类GDIPlane:平面{}
GDIPlane _平面=空;
公共事件事件处理程序DrawingError{add{{U Plane.DrawingError+=value;}remove{{U Plane.DrawingError-=value;}}
}
单击TestControl实例时,属性管理器中的事件列表中不会显示DrawingError
EDIT2:这是原始问题(没有任何解决方法),TestControl的DrawingError事件不会出现:
public interface ISurface { }
public class GDISurface : ISurface { }
public class Plane<T> where T : ISurface
{
public event EventHandler<DrawingErrorEventArgs> DrawingError = null;
public class DrawingErrorEventArgs : EventArgs { T stuff; }
}
public class TestControl : UserControl
{
Plane<GDISurface> _Plane = null;
public event EventHandler<Plane<GDISurface>.DrawingErrorEventArgs> DrawingError { add { _Plane.DrawingError += value; } remove { _Plane.DrawingError -= value; } }
}
公共接口ISurface{}
公共类GDISurface:ISurface{}
公共类平面,其中T:i曲面
{
公共事件EventHandler DrawingError=null;
公共类DrawingErrorEventArgs:EventArgs{T stuff;}
}
公共类TestControl:UserControl
{
平面_平面=零;
公共事件事件处理程序DrawingError{add{{U Plane.DrawingError+=value;}remove{{U Plane.DrawingError-=value;}}
}
这是Visual Studio特有的行为,其原因在于EventHandler没有在其“TEventArgs”上指定协方差(这可能会施加看似愚蠢的限制),并且这些工具没有对代码执行足够的内省,无法生成适当的类型(即使您在构造控件中留下了类型数据的踪迹),因此,看起来VS不支持通用事件属性。您可以考虑提交一个特征请求,但我不建议将其归档为bug,因为它们可以将其标记为“设计”并关闭它。
一般来说,如果您需要事件的通用类型参数,并且需要它们的设计时支持(这是不同的实现关注点),那么您可以考虑将它们包装到特定于表示的外观中(例如,“额外的代码层以满足设计时需要”)
就我个人而言,我会减少你现在使用的泛型类型,这似乎有点过分,如果你不理解泛型类型中的协方差/逆变,可能会在某个时候让你陷入困境,比如现在
但是,要解决您的问题:
考虑使用自定义事件args类,该类可以传输非泛型属性中的数据,还可以使用非泛型EventHandler
event/property。然后,了解事件的“类型”将从泛型类型参数转移到非泛型事件args,而由非泛型事件args负责。如果t args不够,您可以添加一个属性来传递事件类型(或数据类型),以便接收代码能够正确地解释它(当然,假设它还没有通过其他方式知道):
这通常仅用于通过事件链传递数据,通常实现如下:
public class DataEventArgs<T> : EventArgs
{
public T Data { get; set; }
}
为了补充上述内容,以下是非通用事件处理程序的外观:
private void testControl1_DrawingError(object sender, EventArgs e)
{
var genericDrawingErrorEventArgs = e as Plane<GDISurface>.DrawingErrorEventArgs;
if (genericDrawingErrorEventArgs != null)
{
// TODO:
}
}
private void testControl1\u DrawingError(对象发送方,事件参数e)
{
var genericDrawingErrorEventArgs=e作为平面。DrawingErrorEventArgs;
如果(通用)