Created
October 24, 2013 11:16
-
-
Save peace2048/7135362 to your computer and use it in GitHub Desktop.
PropertyChanged イベントを IObservable で監視しやすいように、INotifyPropertyChanged を拡張します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Imports System | |
Imports System.ComponentModel | |
Imports System.Linq | |
Imports System.Linq.Expressions | |
Imports System.Reactive.Linq | |
Imports System.Runtime.CompilerServices | |
''' <summary> | |
''' INotifyPropertyChanged に拡張メソッドを追加し、PropertyChanged イベントを IObservable で監視可能にします。 | |
''' </summary> | |
Public Module PropertyChangedExtensions | |
''' <summary> | |
''' PropertyChanged イベントを IObservable に変換します。 | |
''' </summary> | |
''' <typeparam name="TSender">監視対象の型</typeparam> | |
''' <param name="sender">監視対象</param> | |
''' <returns> | |
''' 基本的に、Reactive の Observable.FromEventPattern と同じですが、 | |
''' Rective の EventPattern は、Sender が Object として格納されていますので、 | |
''' 元の型で格納される PropertyChangedEventPattern で通知します。 | |
''' | |
''' Property 拡張メソッドと共に使用されることを想定しています。 | |
''' </returns> | |
''' <remarks> | |
''' 別スレッドで通信を行い、サーバとの通信状態を IsOnline プロパティに設定すると同時に PropertyChanged で通知するとする。 | |
''' 次のように、記述すれば ObserveOn で MainWindow の UIスレッドで Subscribe できる。 | |
''' <example> | |
''' Dim obj As INotifyPropertyChanged | |
''' obj.AsObservablePropertyChanged().Property(Function(o) o.IsOnline).ObserveOn(MainWindow).Subscribe(Sub(value) StatusLabel.Text = If(value, "オンライン", "オフライン")) | |
''' </example> | |
''' 複数のプロパティを監視する場合は、次のようにも記述できる。 | |
''' <example> | |
''' Dim obj As INotifyPropertyChanged | |
''' Dim propChange = obj.AsObservablePropertyChanged().ObserveOn(MainWindow) | |
''' propChange.Property(Function(o) o.IsOnline).Subscribe(Sub(value) StatusLabel.Text = If(value, "オンライン", "オフライン")) | |
''' propChange.Property(Function(o) o.CurrentWork).Subscribe( | |
''' Sub(work) | |
''' If work Is Nothing Then | |
''' WorkNameLabel.Text = "" | |
''' Else | |
''' WorkNameLabel.Text = work.Name | |
''' End If | |
''' End Sub) | |
''' </example> | |
''' </remarks> | |
<Extension> | |
Public Function AsObservablePropertyChanged(Of TSender As INotifyPropertyChanged)(sender As TSender) As IObservable(Of PropertyChangedEventPattern(Of TSender)) | |
Return From eventPattern In Observable.FromEventPattern(Of PropertyChangedEventArgs)(sender, "PropertyChanged") | |
Select New PropertyChangedEventPattern(Of TSender)( | |
sender:=DirectCast(eventPattern.Sender, TSender), | |
propertyName:=eventPattern.EventArgs.PropertyName) | |
End Function | |
''' <summary> | |
''' PropertyChangedEventPattern の監視可能なシーケンスから、指定したプロパティを抜き出して、プロパティの値を監視可能なシーケンスとして返します。 | |
''' </summary> | |
''' <typeparam name="TSender">プロパティを取得するオブジェクトの型</typeparam> | |
''' <typeparam name="TValue">プロパティの値の型</typeparam> | |
''' <param name="source">PropertyChangedEventPattern の監視可能なシーケンス</param> | |
''' <param name="propertyExpression">プロパティの値を返す式</param> | |
''' <returns>プロパティ値の監視可能なシーケンス</returns> | |
''' <remarks></remarks> | |
<Extension> | |
Public Function [Property](Of TSender As INotifyPropertyChanged, TValue)(source As IObservable(Of PropertyChangedEventPattern(Of TSender)), propertyExpression As Expression(Of Func(Of TSender, TValue))) As IObservable(Of TValue) | |
Dim memberExpression = DirectCast(propertyExpression.Body, MemberExpression) | |
Dim propertyName = memberExpression.Member.Name | |
Dim getter = propertyExpression.Compile() | |
Return From a In source | |
Where a.PropertyName = propertyName | |
Select getter(a.Sender) | |
End Function | |
End Module | |
''' <summary> | |
''' オブジェクトとプロパティ名を保持するクラス。 | |
''' | |
''' INotifyPropertyChanged の拡張メソッドである AsObservablePropertyChanged で使用されます。 | |
''' </summary> | |
''' <typeparam name="TSender">The type of the sender.</typeparam> | |
Public Class PropertyChangedEventPattern(Of TSender As INotifyPropertyChanged) | |
''' <summary> | |
''' Initializes a new instance of the <see cref="PropertyChangedEventPattern(Of TSender)"/> class. | |
''' </summary> | |
''' <param name="pattern">The pattern.</param> | |
Public Sub New(pattern As System.Reactive.EventPattern(Of PropertyChangedEventArgs)) | |
Me.Sender = DirectCast(pattern.Sender, TSender) | |
Me.PropertyName = pattern.EventArgs.PropertyName | |
End Sub | |
''' <summary> | |
''' Initializes a new instance of the <see cref="PropertyChangedEventPattern(Of TSender)"/> class. | |
''' </summary> | |
''' <param name="sender">The sender.</param> | |
''' <param name="propertyName">Name of the property.</param> | |
Public Sub New(sender As TSender, propertyName As String) | |
Me.Sender = sender | |
Me.PropertyName = propertyName | |
End Sub | |
Private _Sender As TSender | |
''' <summary> | |
''' Gets the sender. | |
''' </summary> | |
''' <value> | |
''' The sender. | |
''' </value> | |
Public Property Sender() As TSender | |
Get | |
Return _Sender | |
End Get | |
Private Set(ByVal value As TSender) | |
_Sender = value | |
End Set | |
End Property | |
Private _PropertyName As String | |
''' <summary> | |
''' Gets the name of the property. | |
''' </summary> | |
''' <value> | |
''' The name of the property. | |
''' </value> | |
Public Property PropertyName() As String | |
Get | |
Return _PropertyName | |
End Get | |
Private Set(ByVal value As String) | |
_PropertyName = value | |
End Set | |
End Property | |
End Class |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment