Autor Beitrag
zappo
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 40



BeitragVerfasst: Di 20.10.09 01:19 
Hallo Leute,

das hier ist vermutlich ein einigermassen triviales Problem, aber ich komme schlicht nicht auf die Lösung.
In einer Anwendung habe ich 2 Slider, diese sind voneinander abhängig in der Form, das eine Änderung egal welcher der Slider die Änderung der Werte Minimum, Maximum, + der Selection Start und End Werte beider Slider zur Folge hat...

Nun das Problem,

ich habe eine Funktion

ausblenden C#-Quelltext
1:
2:
3:
4:
public void CalcSliderValues()
{
......
}

In welchem die Werte für die Slider errechnet werden, diese schreibe ich dann gleich in eigenschaften der klasse, an welche ich wiederrum im WPF die Slider gebunden habe, soweit so gut, mit nur einem Slider funktioniert das auch wunderbar... Der Knackpunkt liegt in meinem Aufruf der Funktion, denn die findet statt, sobald sich das "Value" eines Sliders ändert.. und zwar folgendermassen

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
        public int slider2
        {
            get { return _slider2_value; }
            set
            {
                _slider2_value = value;
                CalcSliderValues()
                OnPropertyChanged("slider2");
            }
        }
        public int slider1
        {
            get { return _slider1_value; }
            set
            {
                _slider1_value = value;
                CalcSliderValues()
                OnPropertyChanged("slider1");
            }
        }


Mein Problem ist also, das die Slider sich beim aktualisieren der Werte immer wieder gegenseitig aktualisieren, was zu einem StackOverflow führt... wie kann ich dies umgehen? Kann mir jemand helfen??


Gruß
Sebastian


P.S.
Danke noch einmal, speziell an Kha, für die bisher gegebenen Tips, ihr habt mir als Neuling damit schon so manches erleichtert...


Edit: S***... Thread im falschen Unterforum, glaube hätte in C# gehört.. könnte ein Mod das verschieben? Ist glaub ich besser als noch einmal neu posten...
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 20.10.09 19:47 
Ich sehe drei Möglichkeiten:
  • Je nach Komplexität dieser Beziehung (bzw. du das Gefühl hast, im ViewModel Redundanz zu haben) könnte man das VM auf eine Property reduzieren und für den zweiten Slider einen Value Converter dazwischen schalten. Überhaupt haben Namen wie "Slider" eher wenig im VM zu suchen ;) .
  • Die beste Lösung dürfte sein: OnPropertyChanged aus den Settern entfernen, dafür beide in CalcSliderValues einfügen.
  • Wenn du die vorherige Lösung verallgemeinern bzw. komplett auf INotifyPropertyChanged verzichten willst, schau dir unbedingt das hier an :shock: :
    An easier way to manage INotifyPropertyChanged
    Bringt dir so zwar noch nichts, ich habe die Klasse aber noch etwas erweitert:
    ausblenden volle Höhe C#-Quelltext
    1:
    2:
    3:
    4:
    5:
    6:
    7:
    8:
    9:
    10:
    11:
    12:
    13:
    14:
    15:
    16:
    17:
    18:
    19:
    20:
    21:
    22:
    23:
    24:
    25:
    26:
    27:
    28:
    29:
    30:
    31:
    32:
    33:
    34:
    35:
    36:
    37:
    38:
    39:
    40:
    41:
    42:
    43:
    44:
    45:
    46:
    47:
    48:
    49:
    50:
    51:
    52:
    53:
    54:
    55:
      
    public class Observable<T> : INotifyPropertyChanged
      {
        private T value;

        public Observable()
        {

        }

        public Observable(T value)
        {
          this.value = value;
        }

        public T Value
        {
          get { return value; }
          set
          {
            if (object.Equals(Value, value))
              return;

            SetInternal(value);
            ChangedExternal(thisnew PropertyChangedEventArgs("Value"));
          }
        }

        public void SetInternal(T value)
        {
          if (object.Equals(value, this.value))
            return;

          this.value = value;
          PropertyChanged(thisnew PropertyChangedEventArgs("Value"));
        }

        public static implicit operator T(Observable<T> val)
        {
          return val.value;
        }

        public Observable<U> MapTwoWay<U>(Func<T, U> map, Func<U, T> mapReverse)
        {
          var other = new Observable<U>(map(Value));

          ChangedExternal += delegate { other.SetInternal(map(Value)); };
          other.ChangedExternal += delegate { SetInternal(mapReverse(other.Value)); };

          return other;
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        public event PropertyChangedEventHandler ChangedExternal = delegate { };
      }


    SetInternal ermöglicht genau das, was du brauchst: Die Änderung wird über INotifyPropertyChanged an die View weitergegeben, aber nicht an andere Observables. MapTwoWay ist gleich ein praktisches Beispiel dafür.

    Benutzung:
    ausblenden C#-Quelltext
    1:
    2:
    3:
    4:
    5:
    6:
    7:
    8:
    9:
    Observable<int> Value1 { get; private set; }
    Observable<int> Value2 { get; private set; }

    ...

    ctor:

    Value1 = new Observable<int>();
    Value2 = Value1.MapTwoWay(ConvertValue1ToValue2, ConvertValue2ToValue1);


    Gut, das war eher grob skizziert und vielleicht eher die berühmte Spatzenkanone, aber solange ich nie mehr IPropertyValueChanged selbst implementieren muss, ist es mir recht ;) .


user profile iconzappo hat folgendes geschrieben Zum zitierten Posting springen:
Danke noch einmal, speziell an Kha, für die bisher gegebenen Tips, ihr habt mir als Neuling damit schon so manches erleichtert...

:D
user profile iconzappo hat folgendes geschrieben Zum zitierten Posting springen:
Thread im falschen Unterforum, glaube hätte in C# gehört
Gute Frage. Eigentlich geht es um allgemeine Programm-Logik, aber da sich das Problem in dieser Form sowieso nur in WPF/SL stellt, passt das schon so :) .

_________________
>λ=
zappo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 40



BeitragVerfasst: Mi 21.10.09 01:45 
HM!!!

Sehr interessanter Ansatz das was du da zeigst.... für meinen Teil wahrscheinlich wirklich die Spatzenkanone.. .aber das werde ich mir auf jeden Fall gut merken!!!


Was die Slider angeht.. die slider selber hängen da auch nicht drin, das sind natürlich nur die Werte, an welche diese gebunden werden.... (das darf ich, oder? :-) )

Gelöst habe ich es schliesslich denkbar einfach...

zusätzliche Eigenschaft "sync eingeführt, diese wird in der CalcSliderValues() gesetzt,

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
public void CalcSliderValues()
{
     _slider_sync = false;
     .... Berechnungen;
     _slider_sync = true;
}


In den Eigenschaften welche ich von hier aus setze dann jeweils im Setter abgefragt bevor bei Aktualisierung ausgeführt

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
        public double _sld_value
        {
            get { return sld_value; }
            set
            {
                sld_value = value;
                OnPropertyChanged("_sld_value");
                if (_slider_sync == true)
                {
                    CalcSliderValues();
                }
            }
        }



Schon aktualisieren Sie sich nicht mehr gegenseitig bis in alle Ewigkeit! ;)

Danke wie gesagt trotzdem für die Hilfe.. deinen Ansatz werde ich mir gleich mal Bookmarken und bei einem anderem Problem ausprobieren! ;)

Gruß Sebastian
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mi 21.10.09 15:28 
Da finde ich meinen zweiten Vorschlag aber ehrlich gesagt passender und gleichzeitig genauso simpel. Was passiert bei dir, wenn CalcSliderValues eine Exception wirft ;) ?

user profile iconzappo hat folgendes geschrieben Zum zitierten Posting springen:
die slider selber hängen da auch nicht drin, das sind natürlich nur die Werte, an welche diese gebunden werden
Klar. Aber trotzdem erfüllen diese zwei Properties ja einen Zweck, nach dem sie benannt werden sollten. Control-Namen im VM kommen mir einfach merkwürdig vor.

_________________
>λ=
zappo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 40



BeitragVerfasst: Mi 21.10.09 19:02 
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Da finde ich meinen zweiten Vorschlag aber ehrlich gesagt passender und gleichzeitig genauso simpel. Was passiert bei dir, wenn CalcSliderValues eine Exception wirft ;)


Ja..ok.. da würde meine Lösung ein Problem darstellen! Keine Frage... :/ Deine Zweite hatte ich auch total aus den Augen verloren als ich die Dritte gesehen habe! ;)
*grins*

Allerdings ist es ziemlich unwahrscheinlich das mir CalcSliderValues eine Exception wirft.. das gute Stück hat ja nicht viel zu tun.. trotzdem.. Recht hast du, werde umschwenken!

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:

user profile iconzappo hat folgendes geschrieben Zum zitierten Posting springen:
die slider selber hängen da auch nicht drin, das sind natürlich nur die Werte, an welche diese gebunden werden
Klar. Aber trotzdem erfüllen diese zwei Properties ja einen Zweck, nach dem sie benannt werden sollten. Control-Namen im VM kommen mir einfach merkwürdig vor.


Ja.. ok.. Eine Sache der Konventionen.. daran muss ich mich wohl noch gewöhnen.. stimmt auch... besser jetzt, als gar nicht mehr..

Danke dir für den Hinweis! :-p

Moderiert von user profile iconChristian S.: Quote-Tag repariert