Seiten

Dienstag, 8. März 2011

VB.NET-Version von Beat Kiener's DependencyPropertyChangedListener für Silverlight

Beat Kiener veröffentlichte in seinem Blog vor einiger Zeit einen sehr nützlichen Artikel, in dem er eine von ihm entwickelte DependencyPropertyChangedListener Klasse für Silverlight vorstellte.

Hier geht es zu dem lesenswerten Artikel von Beat Kiener, wo es auch den Quellcode der C#-Version gibt.

Der DependencyPropertyChangedListener ermöglicht es, nach Veränderungen des Werts einer Abhängigkeitseigenschaft zu lauschen und über ein Event hierüber benachrichtigt zu werden. Das ist in vielen Szenarien eine sehr nützliche Sache.

Ich habe den DependencyPropertyChangedListener von Beat Kiener übersetzt nach VB.NET. Denn ich konnte die Klasse in einem VB.NET-Projekt sehr gut brauchen. Beat Kiener war so freundlich und gab mir die Erlaubnis, die von mir übersetzte VB.NET-Version hier in meinem Blog zu veröffentlichen. Vielen Dank nochmal dafür!

Hier also ist der Quellcode der VB.NET-Version (die originalen Kommentare habe ich beibehalten):

DependencyPropertyChangedListener.vb:

Imports System.Windows.Data

Public Class DependencyPropertyChangedListener
#Region "Inner types"

  ' Helper element to make it possible to use the binding engine
  'to get notified when the source element property changes.
  Protected Friend Class RelayObject
    Inherits DependencyObject

    Private Shared _listener As DependencyPropertyChangedListener

    Friend Sub New(ByVal listener As DependencyPropertyChangedListener)
      _listener = listener
    End Sub

    Public Shared ReadOnly ValueProperty As DependencyProperty =
      DependencyProperty.Register("Value",
                                  GetType(Object),
                                  GetType(RelayObject),
                                  New PropertyMetadata(New Object,
                                                       New PropertyChangedCallback(AddressOf OnValueChanged)))

    Public Property Value As Object
      Get
        Return GetValue(ValueProperty)
      End Get
      Set(ByVal value As Object)
        SetValue(ValueProperty, value)
      End Set
    End Property

    Public Shared Sub OnValueChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)

      Dim oldValue As Object = e.OldValue
      Dim newValue As Object = e.NewValue
      Dim source As RelayObject = CType(d, RelayObject)
      RelayObject.OnValueChanged(oldValue, newValue)

    End Sub

    Public Shared Sub OnValueChanged(ByVal oldValue As Object, ByVal newValue As Object)
      _listener.OnValueChanged(oldValue, newValue)
    End Sub

  End Class

#End Region


#Region " Events "

  ' Raises when the dependency property changes.
  Public Event ValueChanged As EventHandler(Of DependencyPropertyValueChangedEventArgs)

#End Region


  ' Holds a reference to the relay object in order that the GC does not collect it
  Private Property RelayInstance As RelayObject

  Public Shared Function Create(ByVal sourceElement As DependencyObject,
                                ByVal propertyPath As String) As DependencyPropertyChangedListener

    ' check input
    If sourceElement Is Nothing Then
      Throw New ArgumentException("sourceElement")
    End If

    If String.IsNullOrWhiteSpace(propertyPath) Then
      Throw New ArgumentException("propertyPath is empty")
    End If

    ' create listener
    Dim listener As DependencyPropertyChangedListener = New DependencyPropertyChangedListener

    ' setup binding
    Dim binding As Binding = New Binding
    binding.Source = sourceElement
    binding.Mode = BindingMode.OneWay

    binding.Path = New PropertyPath(propertyPath)

    ' create relay object
    Dim relay As RelayObject = New RelayObject(listener)

    ' ...the listener holds a reference to the relay object in order that the GC does not collect it
    listener.RelayInstance = relay

    ' set binding
    BindingOperations.SetBinding(relay, RelayObject.ValueProperty, binding)

    Return listener

  End Function


  Public Sub Detach()

    If Me.RelayInstance IsNot Nothing Then
      ' first: reset member to prevent further eventing of ValueChanged event.
      Dim temp As RelayObject = Me.RelayInstance
      Me.RelayInstance = Nothing

      ' second: clear the binding -> raises property changed event...
      temp.ClearValue(RelayObject.ValueProperty)

    End If

  End Sub

  Private Sub OnValueChanged(ByVal oldValue As Object, ByVal newValue As Object)

    ' raise event, but only if the listener is not detached.
    If Me.RelayInstance IsNot Nothing Then

      RaiseEvent ValueChanged(Me, New DependencyPropertyValueChangedEventArgs(oldValue, newValue))

    End If

  End Sub


End Class



DependencyPropertyValueChangedEventArgs.vb:
Public Class DependencyPropertyValueChangedEventArgs
  Inherits EventArgs


  Friend Sub New(ByVal oldValue As Object, ByVal newValue As Object)
    Me.OldValue = oldValue
    Me.NewValue = newValue
  End Sub

  '/// <summary>
  '///  Gets the value of the property before the change.
  '/// </summary>
  Public Property OldValue As Object

  '/// <summary>
  '/// Gets the value of the property after the change.
  '/// </summary>
  Public Property NewValue As Object

End Class


Verwendung in MainPage.xaml.vb:

Partial Public Class MainPage
  Inherits UserControl

  Private listener As DependencyPropertyChangedListener

  Public Sub New()
    InitializeComponent()

    listener = DependencyPropertyChangedListener.Create(Me.txTest, "Text")

    AddHandler listener.ValueChanged,
      New EventHandler(Of DependencyPropertyValueChangedEventArgs)(AddressOf listener_ValueChanged)

    AddHandler btDetach.Click, AddressOf DetachListener

  End Sub

  Private Sub listener_ValueChanged(ByVal sender As Object,
                                    ByVal e As DependencyPropertyValueChangedEventArgs)

    MessageBox.Show(e.NewValue.ToString)

  End Sub

  Private Sub DetachListener(ByVal sender As Object, ByVal e As RoutedEventArgs)

    If listener IsNot Nothing Then
      listener.Detach()
    End If

  End Sub


End Class

Viel Spass damit.

Keine Kommentare:

Kommentar veröffentlichen