【问题标题】:Add an event handler and instanciation of class添加事件处理程序和类的实例化
【发布时间】:2014-12-18 13:07:16
【问题描述】:

我在添加处理程序时遇到问题:我解释一下

这是中介

Public Class ContratClassiqueViewModel
Implements IMediatorContratClassique

Public objucPTClassiqueViewModel As ucPTClassiqueViewModel

#Region "Constructors"

    Sub New(ByVal CtxViewModel As CtxViewModel, ByVal ucPlancheTravaux As ucPTClassiqueViewModel)
        objCtxViewModel = CtxViewModel
        objucPTClassiqueViewModel = ucPlancheTravaux
        objucPTClassiqueViewModel.AddHandlers()
        AddingHandlers()
    End Sub

    Sub New()
        objucPTClassiqueViewModel = New ucPTClassiqueViewModel(True)
        objucPTClassiqueViewModel.AddHandlers()
        AddingHandlers()
    End Sub
#End Region

  Private Sub AddingHandlers()
      AddHandler objucPTClassiqueViewModel.ChangeDateRealisation, AddressOf OnChangeDateRealisation
  End Sub

 Private Sub OnChangeDateRealisation(ByVal DatRealisation As Date?)
        Messagebox.Show("Raised")
 End Sub

End Class

另一个类:

   Public Class ucPTClassiqueViewModel
        Implements IMediatorContratClassique

        Public objucParamPTViewModel As ucParamPTViewModel

        Sub New()

        End Sub


        Sub New(ByRef flag As Boolean)
            objucParamPTViewModel = New ucParamPTViewModel
        End Sub

        Public Sub AddHandlers()
            AddHandler objucParamPTViewModel.ChangeDateRealisation, AddressOf OnChangeDateRealisation
        End Sub

        Private Sub OnChangeDateRealisation(ByVal DatRealisation As Date?)
            RaiseEvent ChangeDateRealisation(DatRealisation)
        End Sub

End class

问题是:当程序使用ContratClassiqueViewModel类的默认构造函数时,它可以工作,但如果它使用其他构造函数:

  Sub New(ByVal CtxViewModel As CtxViewModel, ByVal ucPlancheTravaux As ucPTClassiqueViewModel)
            objCtxViewModel = CtxViewModel
            objucPTClassiqueViewModel = ucPlancheTravaux
            objucPTClassiqueViewModel.AddHandlers()
            AddingHandlers()
        End Sub

方法:

 Private Sub OnChangeDateRealisation(ByVal DatRealisation As Date?)
            Messagebox.Show("Raised")
     End Sub

永远不会到达,因为它似乎将处理程序添加到ucPTClassiqueViewModel 的另一个实例。所以我需要知道:

  1. 为什么会这样?
  2. 我该如何解决?

【问题讨论】:

  • 你不应该“重新附加”objucPTClassiqueViewModel,这应该是班级自己的责任(也不要忘记之后再次删除处理程序!)还有一种方法可以向我们展示您如何使用这些课程?由于它是您的程序,我会假设您可以选择是否将相同的视图模型实例提供给您创建的孩子,所以我不明白您为什么在构造函数之间切换?

标签: .net vb.net oop events


【解决方案1】:

要在类之间共享视图模型,您应该首先创建一个共享视图模型,然后将相同的视图模型附加到所有需要它的类/共享它。

为此,您可以创建一个了解视图模型的工厂方法(如有必要,创建一个尚不存在的工厂方法,或警告用户尚不存在视图模型)。然后,工厂方法将视图模型附加到需要它的类。

在视图模型上抛出的任何事件都会迭代到您的侦听器

Factory 类的示例如下

Public Class ViewModelFactory
    Public Shared Property ViewModel As IViewModel

    Public Shared Function Create(Of T As IHaveViewModel)() As T
        Dim newItem As T = Nothing

        Try
            newItem = Activator.CreateInstance(Of T)()

            If ViewModel Is Nothing Then
                Throw New InvalidOperationException("Cannot create items that have a viewmodel before the viewmodel was created!")
            End If
            ' assign the viewmodel
            newItem.ViewModel = ViewModel

        Catch ex As Exception
            Console.WriteLine("Error creating new {0}\r\nMessage: {1}\r\nStacktrace: {2}", GetType(T).FullName, ex.Message, ex.StackTrace)
        End Try

        Return newItem
    End Function
End Class

这将创建基于接口IHaveViewModel 的类(例如,看起来像这样)

Public Interface IHaveViewModel
    Property ViewModel As IViewModel
End Interface

为了简化侦听器的实现,您可以创建一个抽象类来为您附加任何侦听器,并将 DateChangedEvent 转发给一个可覆盖的方法(或者在我的例子中,一个抽象方法,它必须由任何类实现继承它)。可以使用 dispose 方法来确保在 dispose 类时删除处理程序

Public MustInherit Class WatcherClass
    Implements IHaveViewModel, IDisposable

    Private _viewModel As IViewModel
    Public Property ViewModel As IViewModel Implements IHaveViewModel.ViewModel
        Get
            Return _viewModel
        End Get
        Set(value As IViewModel)
            If Object.ReferenceEquals(_viewModel, value) Then
                Return
            End If
            RemoveModelListeners()
            _viewModel = value
            AddModelListeners()
        End Set
    End Property

    Private Sub AddModelListeners()
        If ViewModel Is Nothing Then
            Return
        End If
        AddHandler ViewModel.DateChangedEvent, AddressOf Me.OnDateInModelChanged
    End Sub

    Private Sub RemoveModelListeners()
        If ViewModel Is Nothing Then
            Return
        End If
        RemoveHandler ViewModel.DateChangedEvent, AddressOf Me.OnDateInModelChanged
    End Sub

    Protected MustOverride Sub OnDateInModelChanged(sender As Object, changeDate As DateTime?)

    Private disposedValue As Boolean

    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                RemoveModelListeners()
            End If
        End If
        Me.disposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

End Class

然后从这个实现继承的任何类都必须实现 DateChanged 处理程序方法,就像这两个类所做的那样(例如)

Public Class ImplementedWatcher
    Inherits WatcherClass

    Protected Overrides Sub OnDateInModelChanged(sender As Object, changeDate As Date?)
        Console.WriteLine("Hello world from {0}", Me.GetType().FullName)
    End Sub
End Class

Public Class SecondWatcher
    Inherits WatcherClass

    Protected Overrides Sub OnDateInModelChanged(sender As Object, changeDate As Date?)
        Console.WriteLine("This one also heard me :)")
    End Sub
End Class

IViewModel 可能如下所示

Public Delegate Sub DateChangedEventHandler(sender As Object, changeDate As DateTime?)

Public Interface IViewModel
    Event DateChangedEvent As DateChangedEventHandler
End Interface

实现可能如下

Public Class ViewModel
    Implements IViewModel

    Public Event DateChangedEvent(sender As Object, changeDate As DateTime?) Implements IViewModel.DateChangedEvent

    Private _date As DateTime?
    Public Property ChangeDate As DateTime?
        Get
            Return _date
        End Get
        Set(value As DateTime?)
            If Object.Equals(value, _date) Then
                Return
            End If
            _date = value
            RaiseDateChanged(_date)
        End Set
    End Property

    Protected Overridable Sub RaiseDateChanged(changeDate As DateTime?)
        RaiseEvent DateChangedEvent(Me, changeDate)
    End Sub

    Public Sub New()
        ' ViewModel
    End Sub
End Class

要测试这些类,以及它们如何相互“交互”,您可以使用这个 main 方法(控制台程序)

Sub Main()
    Dim viewModel As ViewModel = New ViewModel()
    ViewModelFactory.ViewModel = viewModel
    Dim watcher As IHaveViewModel = ViewModelFactory.Create(Of ImplementedWatcher)()
    Dim secondWatcher As IHaveViewModel = ViewModelFactory.Create(Of SecondWatcher)()

    Console.WriteLine("Setting date to today")
    viewModel.ChangeDate = DateTime.Now
    Console.WriteLine("Setting date to tomorrow")
    viewModel.ChangeDate = DateTime.Now.AddDays(1)
    Console.WriteLine("Setting date to next week")
    DirectCast(watcher.ViewModel, ViewModel).ChangeDate = DateTime.Now.AddDays(7)

    DirectCast(watcher, IDisposable).Dispose()
    DirectCast(secondWatcher, IDisposable).Dispose()
    Console.ReadLine()
End Sub

这意味着最终所有具有共享视图模型的类也应该通过 Factory 方法创建,这个方法负责将视图模型添加到潜在的侦听器。任何直接从 ImplementedWatcherSecondWatcher 创建的类也会在获得分配的 ViewModel(通过属性)时进行侦听

通过在 Watcher 类上将 ViewModel 设置为 Nothing,处理程序将被删除,或者您可以通过释放 Watcher 类来实现

我希望这能给你一个继续你的计划的想法?

请注意,您还可以在 IViewModel 类中实现 INotifyPropertyChanged 接口,然后您可能会收到有关 ViewModel 中所有更改的警告(如果您愿意的话)并让侦听器决定他们应该对哪些属性做出反应,那么您不必创建大量事件。

【讨论】:

    猜你喜欢
    • 2011-03-10
    • 2010-12-16
    • 2011-04-05
    • 1970-01-01
    • 2014-09-21
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    相关资源
    最近更新 更多