将事件委托给表单而不创建循环引用

时间:2012-06-19 13:31:39

标签: c# vb.net winforms

由于我正在处理的其他项目需要,我有一个在程序集中的类。 一个类可以称之为Class Factory,创建一组控件,需要附加点击事件处理程序,我有一些算法可以根据某些特征确定多态行为,但相对无关紧要。 由于事件处理程序必须打开不属于我的程序集的特定表单,并且该表单需要此“Factory”类。如果没有创建循环引用,有什么方法可以基本上“委托”表单的处理程序事件来定义?

作为一个简单的工作,我必须维护两个单独的类,一个在项目中,一个在表单中,另一个在程序集中。这显然是错误的方式。

对于标题不是100%肯定,因为我知道我正在尝试做什么但不确定如何去做。

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Me.Width = 1500
    Dim panel As New Panel
    panel.Location = New Point(0, 0)
    panel.Size = New Size(1000, 200)
    panel.BackColor = Color.Yellow
    Me.Controls.Add(panel)
    Dim factory As New DrawFactory
    factory.DrawPanel(panel, 5)
End Sub

以上是与以下代码的单独项目,该代码位于类库中:

Public Class DrawFactory
Private xOffset As Integer = 0
Private Const widthConst As Integer = 50
Public Sub DrawPanel(ByRef panel As Panel, ByVal drawPanels As Integer)
    Application.DoEvents()
    For i As Integer = 0 To drawPanels
        Dim childPanel As New Panel
        childPanel.Location = New Point(xOffset, 0)
        childPanel.Size = New Size(widthConst, panel.Height)
        If i < 1 Then
            childPanel.BackColor = Color.Blue
        Else
            childPanel.BackColor = Color.Pink
        End If
        xOffset = xOffset + widthConst
        ''want to add a handler here to open say form5 which is unknown and undefined in the scope of this class
        panel.Controls.Add(childPanel)
    Next
End Sub
End class

这不是我的实际代码,但是它描绘了我所遇到的问题的问题,我不介意在C#或VB.NET中给出答案。

2 个答案:

答案 0 :(得分:1)

循环引用在技术上不是.NET中的问题。这是COM中的一个问题,因为COM使用引用计数来确定何时需要销毁对象。如果您有两个彼此相互引用的对象,则循环引用将导致对象的引用计数都不会达到零,因此它们永远不会被销毁(导致内存泄漏)。但是在.NET中,CLR使用垃圾收集而不是引用计数。垃圾收集器会定期搜索所有对象,以查找应用程序不再引用的任何对象。然后它会摧毁所有找到的死对象。垃圾收集器足够聪明,可以知道两个或多个仅由彼此引用的对象,而不是其他任何对象都已死亡。因此,在.NET托管代码中,循环引用不再导致内存泄漏,因此不再需要避免它们。

但是,正如所说,是的,您可以将事件处理程序方法作为委托传递给另一个项目中的DrawFactory类。然后,DrawFactory类可以将该事件处理程序添加到它想要的任何事件中。例如:

Public Sub DrawPanel(ByVal panel As Panel, ByVal drawPanels As Integer, ByVal handler As EventHandler)
    For i As Integer = 0 To drawPanels
        Dim childPanel As New Panel
        '...
        AddHandler panel.Click, handler
        panel.Controls.Add(childPanel)
    Next
End Sub

然后,在您的表单上,您需要一个与EventHandler签名匹配的方法,例如:

Private Sub Panel_Click(ByVal sender As Object, ByVal e As EventArgs)
    Form2.Show()
End Sub

然后你可以像这样打电话给工厂:

factory.DrawPanel(panel, 5, New EventHandler(AddressOf Panel_Click))

答案 1 :(得分:0)

是的,我相信你可以做到这一点。点击事件签名如下所示:

private void ButtonOkClicked(object sender, RoutedEventArgs e)
{

}

您的类工厂Create方法可以接受Action,所以:

void Create(Action<object, RoutedEventArgs> clickAction)
{
  var btn = new Button();
  btn.OnClick += clickAction;
}

我希望这会有所帮助,如果没有,请告诉我。