Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Propagate property changes through multiple classes

Tags:

c#

properties

I'm trying to figure out how to properly pass properties through multiple classes. I know I can just implement INotifyPropertyChanged in each class and listen for changes on the property, but this seems to be quite a lot of unnecessary code.

The situation:
I have a class (let's call it Class1) with two dependency properties: FilterStatement (String) and Filter (Filter class). Setting the statement affects the filter and vice versa.
The conversion logic between statement and filter, however, isn't located in Class1, but in Class3 - which Class1 doesn't know directly. In between there is Class2 which just has to pass through the changes. (You can imagine class 1 to 3 beeing Viewmodel, Model and Repository, though in the real situation this doesn't completly match).

public class Class1
{
    public static readonly DependencyProperty FilterProperty = DependencyProperty.Register(
        "Filter",
        typeof(Filter),
        typeof(Class1),
        new FrameworkPropertyMetadata(null));

    public static readonly DependencyProperty FilterStatementProperty = DependencyProperty.Register(
        "FilterStatement",
        typeof(String),
        typeof(Class1),
        new FrameworkPropertyMetadata(null));

    public Filter Filter
    {
        get { return (Filter)GetValue(FilterProperty); }
        set { SetValue(FilterProperty, value); }
    }

    public string FilterStatement
    {
        get { return (string)GetValue(FilterStatementProperty); }
        set { SetValue(FilterStatementProperty, value); }
    }

    public Class2 MyClass2Instance { get; set; }
}

public class Class2
{
    public Class3 MyClass3Instance { get; set; }

    public void ChangeClass3Instance(object someParam) {
        ...  // this can change the instance of MyClass3Instance and is called frome somewhere else
        // when changed, the new Class3 instance has to get the property values of Class1
    }
}

public class Class3
{
    private Filter _filter; // here is where the filter set in Class 1 or determined by the statement set in class 1 has to be put

    public string MyFilterToStatementConversionMemberFunction(Filter filter)
    {
        ...
    }

    public Filter MyStatementToFilterConversionMemberFunction(string statement)
    {
        ...
    }
}

My naive solution would be to duplicate the properties across all three classes, implement INotifyPropertyChanged in Class2 and Class3 and listen to the changes, propagating everything down to Class3 and in Result back up to Class1. Isn't there a better solution to this?

like image 639
Florian Koch Avatar asked Aug 31 '16 09:08

Florian Koch


1 Answers

Actually, while Class1 is not a control (given it is a ViewModel) I don't see a reason to make its properties as DependencyProperty, because implementation of INotifyPropertyChanged should be enough. However, implementation with DependencyProperty should work as well:

public class Class1
{
    public static readonly DependencyProperty FilterProperty =
        DependencyProperty.Register(
            nameof(Filter),
            typeof(Filter),
            typeof(Class1),
            new PropertyMetadata(OnPropertyChanged));

    public static readonly DependencyProperty FilterStatementProperty =
        DependencyProperty.Register(
            nameof(FilterStatement),
            typeof(string),
            typeof(Class1),
            new PropertyMetadata(OnPropertyChanged));

    public Filter Filter
    {
        get { return (Filter)GetValue(FilterProperty); }
        set { SetValue(FilterProperty, value); }
    }

    public string FilterStatement
    {
        get { return (string)GetValue(FilterStatementProperty); }
        set { SetValue(FilterStatementProperty, value); }
    }

    public Class2 MyClass2Instance { get; set; }

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var c = (Class1)d;
        if (c.MyClass2Instance?.MyClass3Instance != null)
        {
            if (e.Property == FilterProperty)
            {
                c.FilterStatement = c.MyClass2Instance.MyClass3Instance.MyFilterToStatementConversionMemberFunction((Filter)e.NewValue);
            }
            else if (e.Property == FilterStatementProperty)
            {
                c.Filter = c.MyClass2Instance.MyClass3Instance.MyStatementToFilterConversionMemberFunction((string)e.NewValue);
            }
        }
    }
}

Please note, Filter.Equals should be implemented properly and conversion methods of the Class3 should return the equal values for equal arguments.

like image 154
Eugene Berdnikov Avatar answered Sep 28 '22 11:09

Eugene Berdnikov