Zwei-Wege-Bindung von einem textbox bis einen Schieberegler in WPF
Ich bin habend die härteste Zeit herauszufinden, ein Weg, ein problem zu lösen, ich habe mit databinding auf einen Schieberegler und ein Textfeld.
Das setup:
der aktuelle Wert des Reglers angezeigt wird innerhalb der textbox. Wenn der Benutzer den Schieberegler kann der Wert spiegelt sich im inneren der textbox. Der Benutzer kann wählen, um den Schieberegler ziehen und loslassen, um den Wert er wählt, klicken Sie irgendwo auf die Schiebereglerleiste, um den Wert oder den Wert manuell eintragen in die texbox. Im letzten Fall wird der eingegebene Wert in der textbox sollten das update auf die position des Reglers.
Die texbox ist zwei-Wege-gebunden an ein datacontext-Eigenschaft während der Schieberegler ist einer Art und Weise gebunden, um die gleiche Eigenschaft. Wenn der Benutzer die Folien, oder klicken Sie auf den Schieberegler tracker, ich benutze die dragcompleted-Ereignis der slider zu informieren und den datacontext der änderung. Wenn der Benutzer klickt auf den tracker auf der anderen Seite nutze ich die OnValueChanged-Ereignis der slider zu informieren und den datacontext (und verwenden Sie eine Flagge, um sicherzustellen, die OnValueChanged wurde nicht ausgelöst durch einen Schieberegler bewegen)
Das problem: Die OnValueChanged Ereignis feuert auch beim initialisieren der Wert des Schiebereglers mit der verbindlichen Wert, so kann ich nicht herausfinden, ob der Wert tatsächlich aus der Benutzer-oder der Bindung.
Könnten Sie bitte vorschlagen, vielleicht und alternativen Weg, um die Bindung zu gewährleisten, können wir unterscheiden zwischen Anwender-update und binding-udpates für den regler?
Thnak Sie!
UPDATE Sorry, ich vergaß zu erwähnen, warum ich mich nicht binden direkt beide Schieberegler und Textfeld zwei Möglichkeiten, wie die unten Antworten vorschlagen. Die Aktualisierung der Daten Kontext-Wert auslösen sollen, einen Anruf zu einem backend-server und das abrufen von Daten aus einer Datenbank. Das problem ist, dass, wenn der Benutzer den Schieberegler, die Sie ständig feuert updates. Ich gehe um das problem, indem Sie nur unter Berufung auf die tatsächliche onValueChanged-Ereignis aufrufen, die DoWhatever Methode. Ich hoffe das ist etwas klarer. Sorry für das weglassen dieser...
Ich schnell zusammen, im folgenden Beispiel für Sie, es zu versuchen.
Die xaml -:
<Window x:Class="SliderIssue.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">
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Slider Name="slider" VerticalAlignment="Top"
ValueChanged="slider_ValueChanged"
Thumb.DragStarted="slider_DragStarted"
Thumb.DragCompleted="slider_DragCompleted"
Value="{Binding Count}"
Width="200"
Minimum="0"
Maximum="100"/>
<TextBox VerticalAlignment="Top"
HorizontalAlignment="Left"
Grid.Column="1"
Width="100"
Text="{Binding Count,Mode=TwoWay,UpdateSourceTrigger=LostFocus}"
Height="25"/>
</Grid>
Der code hinter:
using System.Windows;
namespace SliderIssue
{
///<summary>
///Interaction logic for MainWindow.xaml
///</summary>
public partial class MainWindow : Window
{
private bool _dragStarted;
public MainWindow()
{
InitializeComponent();
var item = new Item();
DataContext = item;
}
private void slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (!_dragStarted)
{
var item = (Item)DataContext;
item.DoWhatever(e.NewValue);
}
}
private void slider_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
_dragStarted = true;
}
private void slider_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
{
_dragStarted = false;
var item = (Item) DataContext;
item.DoWhatever(slider.Value);
}
}
}
Eine einfache Daten-Klasse:
using System.ComponentModel;
namespace SliderIssue
{
public class Item : INotifyPropertyChanged
{
private int _count = 50;
public int Count
{
get { return _count; }
set
{
if (_count != value)
{
_count = value;
DoWhatever(_count);
OnPropertyChanged("Count");
}
}
}
public void DoWhatever(double value)
{
//do something with value
//and blablabla
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
Ich benutze den Veranstaltungen zu ermöglichen, um die Schieberegler zu unterlassen, die Aktualisierung der datacontext-Wert beim ziehen der tracker, bis der Benutzer freigegeben hat, den regler tracker.
InformationsquelleAutor ak3nat0n | 2012-12-28
Du musst angemeldet sein, um einen Kommentar abzugeben.
UPDATE
OK, jetzt sehe ich, warum Sie versuchten, es zu tun so. Ich habe ein paar Vorschläge, die helfen können.
Meine erste ist ein bisschen mehr subjektive, aber ich biete es trotzdem. Wenn das problem Sie versuchen zu lösen, ist die Drosselung Anforderungen an einen back-end-Datenbank, ich würde behaupten, dass dein ViewModel müssen nicht selbst betreffen. Ich würde schieben, die eine Schicht in ein Objekt, das den Aufruf an das back-end auf der Grundlage der aktualisierten Wert überliefert aus dem ViewModel.
Könnten Sie eine poor-man ' s-Drosselung Versuch, durch Aufnahme von
DateTimeOffset.Now
jedes mal, wenn ein Aufruf der Methode zum Abfragen der Backend-DB. Vergleichen Sie diesen Wert mit dem letzten Wert festgehalten. Wenn die Zeitspanne zwischen fällt unter die mindestschwelle, aktualisieren Sie den Wert, zu dem es verglichen wurde, und die Anfrage ignorieren.Könnte man nicht eine ähnliche Sache mit einem timer und der timer zurückgesetzt jedes mal, wenn eine Anfrage gemacht, aber das ist messier.
Wenn der Aufruf wieder von der back-end, diese Schicht wirft ein Ereignis, welches das ViewModel verarbeitet und tut, was es tun muss mit den Daten zurückgegeben.
Als weiteren Vorschlag würde ich auch überprüfen Sie heraus, was die ReactiveExtensions geben Sie. Es dauert ein bisschen, Art wickeln Sie Ihr Gehirn um, wie Sie funktionieren, aber Sie könnte einen
Observable
aus einem Strom von Ereignissen, und verwenden Sie dann dieThrottle()
Methode zum zurückgeben einer anderenObservable
. Abonnieren Sie, dassObservable
und führen Sie Ihre call gibt. Es wäre mehr re-denken, das design und die Architektur Ihrer software, aber es ist faszinierend.Paul Betts schuf eine ganze MVVM-framework basiert auf der Rx genannt ReactiveUI. Ich lernte über die Drosselung Observablen in einem seiner blog-Beiträge hier.
Glück!
ORIGINAL-BEITRAG
Wenn ich verstehe dein problem richtig, es klingt wie Sie wäre, wie die Regler und die TextBox entsprechend die gleiche Eigenschaft DataContext (in der Regel ein ViewModel). Es sieht aus wie Sie versuchen zu duplizieren, was die Bindung Mechanismus von WPF gibt Sie. Ich war in der Lage, eine schnelle Prototyp dieser Arbeit. Hier ist der code, den ich verwendet.
Für die Ansicht, die ich gerade erstellt ein neues Fenster mit diesem Inhalt von dem Fenster.
Beachten Sie, dass der Regler und die TextBox gebunden sind, die gleiche (geschickt benannte) Wert des DataContext. Wenn der Benutzer einen neuen Wert in das Textfeld den Wert, der geändert wird, und den property change notification (im ViewModel) führen Sie den Schieberegler, um aktualisieren Sie Ihren Wert automatisch.
Hier ist der code für die ViewModel (d.h., den DataContext der View).
Mein ViewModel wird abgeleitet von einer Klasse ViewModelBase, die sich um die
INotifyPropertyChanged
- Schnittstelle. DieOnPropertyChanged()
Methode ist in der Basisklasse definiert werden, die nur löst das Ereignis für die Eigenschaft, deren name übergeben wird, als parameter.Schließlich habe ich die Anzeigen und jeweils eine neue Instanz des ViewModel als seine DataContext (ich habe dies direkt in der App
OnStartup()
- Methode für dieses Beispiel).Ich hoffe das hilft Euch gehen in die richtige Richtung.
InformationsquelleAutor Eric Olsson
UPDATE:
Entlang der Linien mit Eric, aber als separaten Vorschlag der Betrieb.
Diese Weise können Sie verwalten die updates, auch wenn ein Benutzer verrückt mit dem Schieberegler ein.
Ich glaube, dass Sie eventuell über Gedanken. Entfernen Sie alle Veranstaltungen, die-off slider und textbox. Wenn der erste Wert (programmgesteuert), sollten Sie nicht rufen Sie Ihren DoWhatever Methode, dann legen Sie Sie in einer check-in-code zu überspringen, die erste Initialisierung....
Ich empfehlen, dass Sie den regler binden zu Zählen, als TwoWay-Modus und haben Sie die Count-Eigenschaft zu tun die anderen Verfahren benötigen Sie wie auf Ihrer entity-Klasse). Keine Notwendigkeit zu prüfen, die für Klicks oder jedem anderen event. Wenn der Benutzer ändert den Wert in der textbox ändert es die slider und Umgekehrt.
Ich habe aktualisiert mein verlangen Griff der Datenbank ein update-Problem.
InformationsquelleAutor ΩmegaMan