Je dois créer une interface utilisateur WPF qui s'aligne sur les mises à jour Fx Rate (Currency + rate) en temps réel et les affiche dans une grille (environ 1000 mises à jour par seconde, ce qui signifie que chaque ligne de la grille mise à jour jusqu'à 1000 fois par seconde). La grille aurait au moins 50 lignes à tout moment. Pour cela, j'ai créé un Viewmodel qui s'abonne aux événements de mise à jour et stocke ces mises à jour dans un dictionnaire concurrent avec la clé comme symbole et comme valeur dans un objet RateViewModel. Ensuite, j'ai une autre collection observable qui a tous ces objets rateviewmodel, et lier cela à une grille.Mise à jour de l'interface utilisateur en temps réel
code:
public class MyViewModel
{
private readonly IRatesService ratesService;
private readonly ConcurrentDictionary<string, RateViewModel> rateDictionary;
private object _locker = new object();
public MyViewModel(IRatesService ratesService)
{
this.ratesService = ratesService;
this.ratesService.OnUpdate += OnUpdate;
rateDictionary = new ConcurrentDictionary<string, RateViewModel>();
RateViewModels = new ObservableCollection<RateViewModel>();
}
private void OnUpdate(object sender, RateUpdateEventArgs e)
{
RateViewModel exisistingRate;
if (!rateDictionary.TryGetValue(e.Update.Currency, out exisistingRate))
{
exisistingRate = new RateViewModel(new Rate(e.Update.Currency, e.Update.Rate));
rateDictionary.TryAdd(e.Update.Currency, exisistingRate);
return;
}
lock (_locker)
{
exisistingRate.UpdateRate(e.Update.Rate);
}
Application.Current.Dispatcher.BeginInvoke(new Action(() => SearchAndUpdate(exisistingRate)));
}
public ObservableCollection<RateViewModel> RateViewModels { get; set; }
private void SearchAndUpdate(RateViewModel rateViewModel)
{
//Equals is based on Currency
if (!RateViewModels.Contains(rateViewModel))
{
RateViewModels.Add(rateViewModel);
return;
}
var index = RateViewModels.IndexOf(rateViewModel);
RateViewModels[index] = rateViewModel;
}
}
J'ai 4 questions sur ce:
Est-il possible que je peux éliminer le ObservableCollection, comme il est conduit à 2 différents datastructures stockant les mêmes éléments - mais ai-je encore mes mises à jour relayées à l'interface utilisateur? J'ai utilisé le dictionnaire concurrent, qui conduit à verrouiller l'opération de mise à jour entière. Y a-t-il une autre façon intelligente de gérer cela plutôt que de bloquer tout le dictionnaire ou d'ailleurs toute infrastructure de données? Ma méthode UpdateRate se verrouille également - toutes mes propriétés sur mon RateviewModel sont en lecture seule sauf le prix, car cela est mis à jour. Y at-il un moyen de rendre cette atomique, s'il vous plaît noter que le prix arrive en double.
Y a-t-il un moyen d'optimiser la méthode SearchAndUpdate, c'est en quelque sorte lié au 1er. En ce moment je crois que c'est une opération O (n).
En utilisant .NET 4.0 et ont omis INPC par souci de concision.
* EDIT: * Pourriez-vous s'il vous plaît m'aider à réécrire cela d'une meilleure manière en tenant compte de tous les 4 points? Psuedocode fera l'affaire.
Merci, -Mike
Pourriez-vous poster un pseudo code pour le point 3 s'il vous plaît? – Mike
Je ne suis pas très clair à ce sujet "Utiliser Interlocked.CompareExchange pour définir un champ privé à 1, si cela renvoie 1 sortie car il y a encore une mise à jour de l'interface utilisateur Si Interlocked.CompareExchange retourné 0, invoquez l'interface utilisateur et déclenchez votre la propriété a changé d'événement et vous met à jour le champ de limitation à 0 (techniquement il y a plus que vous devez faire si vous vous souciez de non x86) "--- Pouvez-vous poster un court extrait de code s'il vous plait? – Mike
@Mike J'ai ajouté du code montrant la technique – Yaur