添加事件处理程序和类的实例化

时间:2014-12-18 13:07:17

标签: .net vb.net oop events

我有添加处理程序的问题:我解释

这是中介

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. 我该如何解决?

1 个答案:

答案 0 :(得分:1)

要在类之间共享viewmodel,首先应创建一个共享的viewmodel,然后将所有需要它/共享它的类附加到同一个viewmodel。

为此,您可以创建一个Factory方法,该方法知道viewmodel(如果需要,还会创建一个尚未存在的视图模型,或警告用户尚未存在视图模型)。然后,工厂方法将viewmodel附加到需要它的类。

然后,在viewmodel上抛出的任何事件都将迭代到您的侦听器

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方法确保在处理类

时删除处理程序
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

测试这些课程,以及他们如何互动"彼此,你可以使用这个主要方法(控制台程序)

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

这意味着最终所有具有共享viewmodel的类也应该通过Factory方法创建,这个类可以将viewmodel添加到潜在的侦听器。直接从ImplementedWatcherSecondWatcher创建的任何类,当他们获得分配的ViewModel(通过属性)时,也会监听

通过在Watcher类上将ViewModel设置为Nothing,将删除处理程序,或者您可以通过处理Watcher类来执行此操作

我希望能让您继续执行您的计划吗?

作为一个注释,您还可以将INotifyPropertyChanged接口实现到IViewModel类中,然后您可以收到有关ViewModel中所有更改的警告(如果您愿意)并让侦听器决定它们属于哪些属性应该做出反应,那么你就不必创造大量的活动。