2016-08-31 85 views
8

Próbuję dowiedzieć się, jak prawidłowo przekazać właściwości za pośrednictwem wielu klas. Wiem, że mogę zaimplementować INotifyPropertyChanged w każdej klasie i posłuchać zmian w obiekcie, ale wydaje się, że jest to dość niepotrzebny kod.Propagowanie zmian właściwości za pomocą wielu klas

Sytuacja:
Mam klasy (nazwijmy go Class1) z dwoma właściwościami Zależność: FilterStatement (string) i Filter (klasa filtra). Ustawienie instrukcji wpływa na filtr i odwrotnie.
Logika konwersji między instrukcją a filtrem nie znajduje się jednak w Class1, ale w Class3 - która Class1 nie zna bezpośrednio. Pomiędzy nimi jest Class2, który musi przejść przez zmiany. (Możesz sobie wyobrazić, że klasy od 1 do 3 to Viewmodel, Model i Repozytorium, chociaż w rzeczywistości sytuacja ta nie pasuje całkowicie).

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) 
    { 
     ... 
    } 
} 

Mój naiwny rozwiązaniem byłoby powielić właściwości we wszystkich trzech klasach, wdrożyć INotifyPropertyChanged w Class2 i Class3 i słuchać zmian, propagowanie wszystko w dół do Class3 a wynik z powrotem do Class1. Czy nie ma lepszego rozwiązania?

+0

Nie możesz użyć komunikatora takiego jak ten w świetle MVVM. Zasadniczo jest to zaprojektowane tak, aby można było powiadamiać o zmianach właściwości na maszynach wirtualnych, które nie muszą się wzajemnie znać. – Keithin8a

+0

Obecnie nie używam tego, a ja chciałbym go użyć do tego celu ... ale tak, masz rację, to może być rozwiązanie –

+1

Tak, dlatego pomyślałem, że zamieściłbym komentarz zamiast Odpowiedź. Wygląda na to, że mógłbyś pójść w drogę, nie robiąc tego, co trzeba, ponieważ uważasz, że jest lepszy sposób na zrobienie tego. Ale znasz swój projekt lepiej ode mnie, więc jestem pewien, że istnieje powód, po prostu bądź ostrożny;) – Keithin8a

Odpowiedz

3

Faktycznie, podczas Class1 nie jest kontrola (biorąc pod uwagę, że jest to ViewModel) Nie widzę powodu, aby jego właściwości jako DependencyProperty, ponieważ realizacja INotifyPropertyChanged powinno wystarczyć. Jednak realizacja z DependencyProperty powinien działać także:

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); 
      } 
     } 
    } 
} 

Uwaga Filter.Equals powinny być realizowane prawidłowo i metody konwersja Class3 należy zwrócić równe wartości dla równych argumentów.

+0

ok, teraz rozumiem, co miałeś na myśli przez "bezpośrednio" - muszę pomyśleć o odpowiedzialności, ale to wygląda dobrze. Miałem skupić się na wydarzeniach, aby wymyślić to rozwiązanie –

0

Myślę, że zbytnio to komplikujesz. Obserwowalny wzór lepiej pasuje do implementacji interfejsu użytkownika. Dlaczego nie kodujesz w logice Class3, która ustawia wszystkie własności w Class1? Uważam, że narzędzie ustawiające przeciążenia FilterStatment i Filter w Class1, które jest również ViewModel jest dobrym rozwiązaniem. Im prostsze rozwiązanie, tym lepsze.

+0

Chociaż 'Class1' zna' Class2' i 'Class2' zna' Class3', to nie jest prawdą odwrotnie - Nie mogę ustawić właściwości 'Class1' z' Class3', a także nie chcę aby to zrobić, ponieważ obowiązki są błędne. –

+0

Myślę, że jeśli opublikujesz kod, będzie łatwiej. – mati

+0

Zbuduję przykład struktury klasowej –