Liaison bilatérale textbox au curseur B. WPF

Il est plus difficile pour moi de trouver un moyen de résoudre le problème qui s'est produit avec mes données reliant le curseur et textbox.

Réglage

:
La valeur actuelle du curseur est affichée à l'intérieur textbox. Lorsque l'utilisateur fait glisser le curseur, la valeur est reflétée à l'intérieur. textbox. L'utilisateur peut faire glisser le curseur et le relâcher sur la valeur sélectionnée, cliquez sur n'importe où dans le chemin de piste pour définir la valeur ou entrez la valeur manuellement dans la zone de texte. Dans ce dernier cas, la valeur entrée dans le champ textbox, Doit être mis à jour la position du curseur.

Texbox Bilatéral attaché à la propriété datacontext, Tandis que le curseur est attaché unilatéralement à la même propriété. Lorsque l'utilisateur glisse ou clique sur le Slider Tracker, j'utilise l'événement dragcompleted curseur à notifier datacontext Sur le changement. D'autre part, lorsque l'utilisateur clique sur le suivi, j'utilise un événement OnValueChanged Curseur pour notification datacontext /et utiliser le drapeau pour vous assurer que OnValueChanged n'a pas été causé en déplaçant le curseur/

Problème

: un événement OnValueChanged Même lors de l'initialisation de la valeur du curseur avec la valeur de liaison, je ne peux donc pas comprendre si cette valeur provient vraiment de l'utilisateur ou de la liaison.

Pourriez-vous suggérer, peut-être et une solution alternative de faire obligation de vous assurer que nous pouvons distinguer la mise à jour de l'utilisateur et la liaison udpates Pour un curseur?
Thnak tu!

Mettre à jour

Désolé, j'ai oublié de mentionner pourquoi je ne m'associe pas directement comme slider, donc je. textbox De deux manières, comme suggérant les réponses ci-dessous. Il est supposé que la mise à jour de la valeur de contexte de données appellera le serveur interne et récupérera les données de la base de données. Le problème est que lorsque l'utilisateur fait glisser le curseur, il commence constamment à des mises à niveau. Je ne vais pas perdre le problème, ne contenant que sur l'événement réel. onValueChanged Appeler la méthode DoWhatever. J'espère que c'est un peu plus clair. Désolé, je le mets enfoncé ...

J'ai rapidement collecté l'échantillon ci-dessous afin que vous puissiez essayer.

DANS xaml

:


<window height="350" title="MainWindow" width="525" x:class="SliderIssue.MainWindow" xmlns="[url=http://schemas.microsoft.com/winfx/2006/xaml/presentation"]http://schemas.microsoft.com/w ... ot%3B[/url] xmlns:x="[url=http://schemas.microsoft.com/winfx/2006/xaml">]http://schemas.microsoft.com/w ... gt%3B[/url]
<grid horizontalalignment="Center" verticalalignment="Center">
<grid.columndefinitions>
<columndefinition></columndefinition>
<columndefinition></columndefinition>
</grid.columndefinitions>
<slider maximum="100" minimum="0" name="slider" thumb.dragcompleted="slider_DragCompleted" thumb.dragstarted="slider_DragStarted" value="{Binding Count}" valuechanged="slider_ValueChanged" verticalalignment="Top" width="200"></slider>
<textbox grid.column="1" height="25" horizontalalignment="Left" text="{Binding Count,Mode=TwoWay,UpdateSourceTrigger=LostFocus}" verticalalignment="Top" width="100"></textbox>
</grid>



Pour le code

:


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


Classe de données simple

:


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


</double></window>
Invité:

Hannah

Confirmation de:

Mettre à jour:

Approximativement comme avec Eric, mais comme une proposition distincte de l'opération.

Attachez les deux éléments afin qu'ils soient considérés comme bilatéraux, comme je l'ai suggéré ci-dessous.

Créez une minuterie qui fonctionne chaque seconde en vérifiant deux variables.

/Timer Check #1/ Vérifie si la demande de base de données est effectuée /Par exemple, drapeau logique/. Si cela est vrai, alors elle ne fait rien. S'il n'y a pas d'opération /false/, Il passe à l'étape 4.

/Chérif chinger #2/ Il vérifie si le compteur a changé. Si un count Changé, il définit le drapeau actuel de la demande de données. /Comme trouvé/Utilisé dans la chasse 3/, Initie un appel de base de données asynchrone et complète le travail.

/Appeler l'action de base de données/ Reçoit des données de base de données et des mises à jour de manière appropriée VM. Il définit le drapeau actuel de la requête de données pour false, Ce qui vous permet de vérifier la minuterie pour lancer une nouvelle demande si le compteur est modifié.

Ainsi, vous pouvez gérer les mises à jour, même si l'utilisateur vient fou du curseur.

Je pense que vous avez peut-être trop pensé à ce sujet. Supprimer tous les événements du curseur et textbox. Si la première valeur /logiciel spécifié/ ne devrait pas appeler votre méthode DoWhatever, Qui mettent une tique dans ce code pour sauter la première initialisation ....

Je vous recommande de faire un curseur de liaison à Count comme régime TwoWay et faire une propriété Count Effectuer un autre processus dont vous avez besoin /Comme indiqué dans votre classe d'entité/. Il n'est pas nécessaire de vérifier la présence de clics ni d'autres événements. Si l'utilisateur modifie la valeur dans textbox, Il change le curseur et vice versa.


<slider maximum="100" minimum="0" name="slider" value="{Binding Count, Mode=TwoWay}" verticalalignment="Top" width="200"></slider>
<textbox grid.column="1" height="25" horizontalalignment="Left" text="{Binding Count,Mode=TwoWay,UpdateSourceTrigger=LostFocus}" verticalalignment="Top" width="100"></textbox>

Christine

Confirmation de:

UPDATE

39, Maintenant, je comprends pourquoi tu as essayé de le faire exactement. J'ai quelques propositions qui peuvent aider.



Mon premier est un peu plus confiant, mais je l'offre néanmoins. Si le problème que vous essayez de décider, c'est d'étrangler des demandes à la base de données interne, je dirais que votre ViewModel ne devrait pas s'inquiéter à ce sujet. Je repoussierais le calque dans l'objet qui appelle la partie serveur en fonction de la valeur mise à jour transmise de ViewModel.

Vous pouvez créer une tentative pour étrangler le pauvre homme, l'enregistrement
DateTimeOffset.Now

Chaque fois qu'un appel est effectué pour une demande de fin de compte. DB. Comparez cette valeur avec la dernière valeur enregistrée. Si la valeur TimeSpan between Falls en dessous de votre seuil minimal, mettez à jour la valeur avec laquelle il est comparé et ignore la demande.

Vous pouvez faire la même chose avec la minuterie et vider la minuterie à chaque fois que la demande est faite, mais c'est encore plus confus.

Lorsque l'appel est renvoyé de la partie serveur, ce niveau provoque un événement qui traite ViewModel Et fait tout ce qu'il doit faire avec des données retournées.

Comme une autre offre, j'aurais aussi vérifié ce qui vous donne ReactiveExtensions. Il faut un peu de temps pour comprendre comment ils travaillent, mais vous pouvez créer
Observable

À partir du flux d'événements, puis utilisez la méthode
Throttle//

, Pour retourner l'autre
Observable

. Vous vous abonnez-vous à ceci
Observable

Et effectuez votre appel là-bas. Cela nécessiterait une plus grande repense de la conception et de l'architecture de votre logiciel, mais elle intrigue.

Paul Betts a créé toute une structure MVVM, Basé sur Rx intitulé
http://www.reactiveui.net
. J'ai d'abord appris que l'étranglement de ceux observés dans l'un de ses poteaux de blog
http://blog.paulbetts.org/inde ... lper/
.

Bonne chance!

Publication originale

Si je comprends votre problème correctement, cela sonne comme si vous souhaitez le curseur, et TextBox Reflété la même propriété DataContext /généralement cette ViewModel/. On dirait que vous essayez de dupliquer ce qui vous donne un mécanisme contraignant WPF. J'ai réussi à obtenir rapidement le prototype de ce travail. Voici le code que j'ai utilisé.

Pour représenter, j'ai simplement créé une nouvelle fenêtre avec ceci comme contenu de la fenêtre.


<stackpanel>
<slider margin="16" value="{Binding TheValue}"></slider>
<textbox margin="16" text="{Binding TheValue}"></textbox>
</stackpanel>


Notez que le curseur et TextBox attaché au même /intelligemment appelé/ sens DataContext. Lorsque l'utilisateur entre une nouvelle valeur dans TextBox, La valeur changera et notifie le changement de propriété /dans ViewModel/ Appelez le curseur Mettez automatiquement à jour votre valeur.

Voici le code pour ViewModel /c'est à dire DataContext représentation/.


class TextySlideyViewModel : ViewModelBase
{
private double _theValue;

public double TheValue
{
get { return _theValue; }
set
{
if/_theValue == value/
return;

_theValue = value;
OnPropertyChanged/"TheValue"/;
}
}
}


My ViewModel est dérivé de la classe ViewModelBase, qui implémente l'interface
INotifyPropertyChanged

. Méthode
OnPropertyChanged//

Déterminé dans la classe de base, qui provoque simplement un événement pour une propriété dont le nom est transmis en tant que paramètre.

Enfin, j'ai créé une idée et j'ai nommé une nouvelle copie. ViewModel Tel quel DataContext /Je l'ai fait directement dans la méthode
OnStartup//

Applications pour cet exemple/.

J'espère que cela vous aidera à bouger dans la bonne direction.

Pour répondre aux questions, connectez-vous ou registre