Slider.Value ändert sich bei der Einstellung Minimum, wenn dies nicht der Fall ist

8

Kurz gesagt:
Unter bestimmten Umständen wird die Einstellung von Slider.Minimum Slider.Value anpassen, obwohl der aktuelle Wert größer als das neue Minimum ist.

Code: (sollte reproduzierbar sein)
MainWindow.xaml:

%Vor%

MainWindow.xaml.cs:

%Vor%

Zu reproduzierende Schritte:
1. Im Debug-Modus ausführen.
2. Bewegen Sie den Schieberegler ganz nach rechts.
3. Drücken Sie die Schaltfläche "Schrumpfgrenzen".
4. Drücken Sie die Schaltfläche "Grenzen wachsen".

Erwartete Ausgabe:

%Vor%

Slider bleibt bei 8.

Tatsächliche Ausgabe:

%Vor%

(Beachten Sie den zusätzlichen "Wert geändert: 1")
Slider springt auf 1.

Hinweis:
Binding Slider.Value OneWayToSource (oder TwoWay) zu einer doppelten Eigenschaft, behebt das Problem.

Frage:
Warum passiert das?

Theorie:
Ich bin mir ziemlich sicher, dass es etwas mit Value Coercion zu tun hat . Es scheint folgendes zu passieren:
1. Wert auf 1 setzen programmatic setzt Wert "Grundwert". Es liegt zwischen den Standardwerten für Minimum und Maximum, also ist der "effektive Wert" genau gleich.
2. Die Einstellung von Minimum und Maximum ändert nichts, weil der Wert immer noch dazwischen liegt.
3. Manuelles Verschieben des Schiebereglers nach rechts ändert scheinbar den "effektiven Wert", aber aus irgendeinem seltsamen Grund nicht den "Basiswert".
4. Durch erneutes Erhöhen der Grenzen wird der Zwangsrückruf aufgerufen, der erkennt, dass der (falsche) "Basiswert" zwischen dem neuen Minimum und Maximum liegt und den "effektiven Wert" wieder auf diesen Wert zurückstellt.

Wenn wir annehmen, dass dies tatsächlich geschieht, führt uns das zu folgender Frage:
Warum zieht der Slider (3.) den "Basiswert" nicht manuell an?

    
Tim Pohlmann 17.08.2015, 14:43
quelle

1 Antwort

6

Ich bin mir nicht sicher, was der Anwendungsfall ist, aber dieses Problem könnte wahrscheinlich vermieden werden, wenn Sie MVVM verwenden und alles gebunden ist. Wenn es das ist, was du tust, und das ist nur eine andere Möglichkeit, das Problem zu reproduzieren, einen guten Fund.

Sehen Sie sich den Slider Quellcode an . Ich konnte das Problem nicht genau bestimmen, aber ich verstehe besser, dass ein interner Wert verwendet wird.

Fügen Sie 2 Schaltflächen hinzu und ändern Sie Minimum oder Maximum nur in den Ereignishandlern für alle Schaltflächen:

%Vor%

Klicken Sie beim Start auf MyButton1 und MyButton2 :

%Vor%

Sie können sehen, intern speichert es den ursprünglichen Startwert und stellt es wieder her, wenn der Bereich es anzeigen kann, es setzt es zurück, was es war. Wenn Sie beim Start nur das Maximum ändern (ohne Schieberegler zu verschieben), wird die Value -Eigenschaft nicht geändert, da Value im aktuellen Bereich liegt:

%Vor%

Wenn Sie jedoch das Schiebereglermaximum auf 20 ändern, dann ändern Sie Maximum = 8 und Minimum = 1.6 , Minimum ist jetzt außerhalb des Bereichs von (intern) Value (1) und verwendet Maximum Wert für es ist Value . Wenn Sie es erneut anwachsen, legen Sie Minimum = 0.5 und Maximum = 20 fest, und da der interne Wert = 1 ist und zwischen 0,5 und 20 liegt, wird Value wieder auf 1 gesetzt.

Ich habe eine Problemumgehung gefunden, und das setzt den internen Wert jedes Mal zurück, wenn Sie den Bereich ändern. Zum Zurücksetzen legen Sie einfach Slider.Value erneut fest. Wenn Sie dies tun, nachdem Sie Maximum und Minimum geändert haben, wird der Wert beibehalten, falls der alte Wert nicht im Bereich des neuen Bereichs liegt. Also nehmen Sie Ihre ursprüngliche Implementierung:

%Vor%

Ausgabe (entspricht Ihren Erwartungen):

%Vor%

Bearbeiten

Der Link zum Wertausgleich ist sehr hilfreich. Ich bin mir nicht sicher, ob deine Frage eine zweite Frage wäre, aber ich glaube, ich habe die Antwort gefunden.

Wenn Sie das Slider (technisch das Thumb mit dem Track ) verwenden, stellen Sie sicher, dass das Thumb riding around an das Slider.Value über Slider.UpdateValue wird aufgerufen. Dieses Problem ist nun, dass SetCurrentValueInternal nicht Open Source ist :( Was wir daraus schließen können ist, dass die Mystery-Funktion ValueProperty nicht erzwingt, sondern nur den Grundwert ("gewünscht") setzt. Probieren Sie:

%Vor%

Wenn Sie so vorgehen, sehen Sie, dass Value zwar von 20 auf 8 abfällt, die Sekunde, in der Sie ValueProperty tatsächlich erzwingen, wenn sie auf 8 abfällt, sich aber in 1.6 ändert. Genau das passiert, wenn Sie die Reichweite erhöhen. Nachdem Sie Max oder Min festgelegt haben, wird die Wertänderung angezeigt, da die Werteigenschaft erneut erzwungen wird. Versuchen Sie, Max und Min zu spiegeln:

%Vor%

Das lässt dich immer noch denken, wie kann es daran denken, wenn möglich wieder zu 1 zurückzukehren, gibt es eine effektive Basis und erste Werte? Ich bin mir nicht sicher.

Tatsächlich versuchen Sie das.

  1. Starten Sie die Anwendung
  2. Bewegen Sie den Daumen ganz nach rechts (Wert = 20)
  3. Schrumpfrahmen (Wert = 8)
  4. Nimm den Daumen und bewege ihn nach links und dann ganz nach rechts (Wert = 8)
  5. Dann wachsen Grenzen

Nach Schritt 5 werden Sie feststellen, dass Value immer noch gleich 8 ist. So habe ich herausgefunden, dass es etwas mit dieser Mystery-Funktion zu tun hat.

Hinweis: Mein Gehirn ist wieder tot. Wenn das nicht klar ist, entschuldige ich mich, ich muss zurückkommen und es bearbeiten.

Bearbeiten 2

Zum einen rufen sowohl SetCurrentValueInteral als auch SetValue beide SetValueCommon auf. Die Differenz ist SetCurrentValueInternal wertet den aktuellen Wert mit dem Basiswert neu aus, da das Coerce-Flag auf "True" gesetzt ist. (behält den Wert von Min / Max bei), ref .

Durch meine Suche habe ich herausgefunden, dass SetCurrentValue und SetValue zwei völlig verschiedene Ergebnisse haben, und zwar: die Nötigung angeben ( IsInternal scheint nicht verwendet zu werden, wenn die gebundene Eigenschaft vom Werttyp ist) .

Mein Beweis ist Dokumentation , die besagt :

  

"Die SetCurrentValue-Methode stellt eine weitere Möglichkeit zum Festlegen einer Eigenschaft dar, liegt jedoch nicht in der Rangfolge. Stattdessen können Sie mit SetCurrentValue den Wert einer Eigenschaft ändern, ohne die Quelle eines vorherigen Werts zu überschreiben. Sie können SetCurrentValue verwenden Wann immer Sie einen Wert festlegen möchten, ohne diesem Wert den Vorrang eines lokalen Wertes zu geben ... "

Damit ändert sich das Verschieben von Thumb von Slider nicht auf den Basiswert, weil es SetCurrentValueInternal aufruft.

Wenn Sie Value manuell ändern, ändert sich der Basiswert außerdem, weil er SetValue aufruft. Die ValueProperty -Abhängigkeitseigenschaft definiert, wie mithilfe des CoerceValueCallback , wie im letzten Absatz hier Im Detail, was in Slider.Value passiert,

  

Die Koerzition interagiert so mit dem Basiswert, dass die Zwangsbedingungen angewendet werden, da diese Bedingungen zu der Zeit existieren, aber der Basiswert bleibt erhalten. Wenn Zwangsbedingungen später aufgehoben werden, wird der Zwang den nächstmöglichen Wert zu diesem Basiswert zurückgeben, und möglicherweise wird der Zwangseinfluss auf eine Eigenschaft aufhören, sobald alle Beschränkungen aufgehoben sind.

Natürlich lese ich weiter Abhängigkeits-Callbacks und Validierung - Erweiterte Zwangs-und Callback-Szenarien und gefunden:

  

Zum Beispiel könnten Sie im Min / Max / Current-Szenario wählen, ob Minimum und Maximum benutzerdefinierbar sein sollen. Wenn dies der Fall ist, müssen Sie möglicherweise erzwingen, dass Maximum immer größer als Minimum ist und umgekehrt. Wenn dieser Zwang aktiv ist und Maximum auf Minimum reduziert wird, bleibt Current in einem nicht setzbaren Zustand, da er von beiden abhängig ist und auf den Bereich zwischen den Werten beschränkt ist, der null ist. Dann, wenn Maximum oder Minimum eingestellt sind, scheint Current einem der Werte zu folgen, weil der gewünschte Wert von Current immer noch gespeichert wird und versucht, den gewünschten Wert zu erreichen, wenn die Beschränkungen gelockert werden.

Zusammenfassend denke ich, dass dies in Slider so gestaltet ist, weil es so codiert ist, dass Value immer zwischen Minimum und Maximum liegen muss. Die Value folgen der Eigenschaft Maximum , und wenn Bedingungen aufgehoben werden (der aktuelle Wert liegt im Bereich des Basiswerts), wird die Eigenschaft value auf ihren ursprünglichen Wert zurückgesetzt.

Schließlich hat IMO WPF den Schieberegler so entworfen, weil WPF Hand in Hand mit der Datenbindung geht. Ich nehme an, dass sie unter der Annahme entworfen wurden, dass Entwickler die Datenbindung voll ausnutzen würden, und würden die Logik implementieren, um zu verhindern, dass ungültige Werte verwendet werden.

    
Kcvin 17.08.2015, 21:02
quelle

Tags und Links