Marcel
Marcel

Reputation: 2158

Binding between properties of two objects that both implements INotifyPropertyChanged in code

I am trying to bind two properties from two different object that both implements INotifyPropertyChanged in code:

    public class ClassA : INotifyPropertyChanged
    {
        // leaving out the INotifyPropertyChanged Members for brevity

        public string Status
        {
            get { return _Status; }
            set { _Status = value; RaiseChanged("Status"); }
        }

    }

    public class ClassB : INotifyPropertyChanged
    {
        // leaving out the INotifyPropertyChanged Members for brevity

        public string Status
        {
            get { return _Status; }
            set { _Status = value; RaiseChanged("Status"); }
        }

    }

Is there a way I can bind these two properties in code together something like I would do if one of them was a 'proper' dependency property? Something like this?

ClassA classA = new ClassA();
ClassB classB = new ClassB();

Binding bind = new Binding("Status");
bind.Source = classA;
classB.SetBinding(ClassB.StatusProperty, bind);

Thanks!

Upvotes: 5

Views: 2703

Answers (4)

Zodman
Zodman

Reputation: 3924

You can't. The property system relies on the registration of a DependencyProperty to attach the binding to. As suggested, you can get around this by monitoring PropertyChanged and handling the changes yourself, but to use bindings in the property system you must use a DependencyProperty.

MSDN states this in the remarks section here.

Upvotes: 0

VoteCoffee
VoteCoffee

Reputation: 5117

I ended up having to make one or both a dependency object.

XAML:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBox Text="{Binding Path=Obj1.Status}"/>
        <TextBox Text="{Binding Path=Obj2.Status}"/>
    </StackPanel>
</Window>

Code:

Class MainWindow
    Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
        Me.DataContext = New SomeViewModel
    End Sub
End Class

Public Class SomeViewModel
    Implements ComponentModel.INotifyPropertyChanged

    Protected _Obj1 As SomeClass
    Public ReadOnly Property Obj1 As SomeClass
        Get
            Return _Obj1
        End Get
    End Property
    Protected _Obj2 As SomeClass
    Public ReadOnly Property Obj2 As SomeClass
        Get
            Return _Obj2
        End Get
    End Property

    Public Sub New()
        _Obj1 = New SomeClass
        _Obj2 = New SomeClass
        NotifyPropertyChanged("Obj1")
        NotifyPropertyChanged("Obj2")

        Dim StatusBinding As New Binding("Status") With {.Source = Obj2, .Mode = BindingMode.TwoWay}
        BindingOperations.SetBinding(Obj1, SomeClass.StatusProperty, StatusBinding)
    End Sub

    Private Sub NotifyPropertyChanged(<Runtime.CompilerServices.CallerMemberName()> Optional ByVal propertyName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New ComponentModel.PropertyChangedEventArgs(propertyName))
    End Sub
    Public Event PropertyChanged(sender As Object, e As ComponentModel.PropertyChangedEventArgs) Implements ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class

Public Class SomeClass
    Inherits DependencyObject
    Implements ComponentModel.INotifyPropertyChanged

    Public Shared ReadOnly StatusProperty As DependencyProperty = DependencyProperty.Register(name:="Status", propertyType:=GetType(String), ownerType:=GetType(SomeClass), typeMetadata:=New PropertyMetadata(propertyChangedCallback:=AddressOf OnDependencyPropertyChanged))

    Private Shared Sub OnDependencyPropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        d.SetValue(e.Property, e.NewValue)
    End Sub

    Protected _Status As String
    Public Property Status As String
        Set(value As String)
            If value <> Me._Status Then
                Me._Status = value
                NotifyPropertyChanged()
            End If
        End Set
        Get
            Return _Status
        End Get
    End Property

    Private Sub NotifyPropertyChanged(<Runtime.CompilerServices.CallerMemberName()> Optional ByVal propertyName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New ComponentModel.PropertyChangedEventArgs(propertyName))
    End Sub
    Public Event PropertyChanged(sender As Object, e As ComponentModel.PropertyChangedEventArgs) Implements ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class

Upvotes: 0

Mike Marynowski
Mike Marynowski

Reputation: 3439

Late response, but...KISS:

ClassA classA = new ClassA();
ClassB classB = new ClassB();

classA.PropertyChanged += (s, e) => {
    if (e.PropertyName == "Status")
        classB.Status = classA.Status;
};

Voila, "binding" between INPC objects :) You can easily create a very simple helper class that does this for you with a single method call if you plan to do this often.

Upvotes: 3

Scott Godfrey
Scott Godfrey

Reputation: 671

You can actually create a seperate object with just that property and assign from within your Status Changed classes. If you make it public, both classes should be able to get/set the property.

Upvotes: 0

Related Questions