3
votes

Comment mettre à jour la propriété dans l'interface utilisateur à l'aide de MVVM dans la routine

Je veux créer un compte à rebours. Le problème est que ma solution n'affiche que la valeur de début 10 et la dernière valeur 1 après 10 secondes. Bien sûr, j'ai implémenté l'interface INotifyPropertyChanged. Des suggestions pour cette solution?

<Button Content="Generuj"  Command="{Binding ButtonStart}"></Button>
<TextBox  Text="{Binding Counter, Mode=OneWay}"></TextBox>

private void ButtonStartClick(object obj)
{
    for (int i = 10; i > 0; i--)
    {
         System.Threading.Thread.Sleep(1000);
         Counter = i;
    }
}


2 commentaires

Counter doit être une propriété, doit implémenter INotifyPropertyChanged. Thread.Sleep (1000); est exécuté à partir du thread GUI -> cela bloque les mises à jour de l'interface graphique. Vous remarquerez un sommeil de 10 secondes et le compteur étant alors mis à 0.


Vous avez lancé le code à partir d'un clic de bouton. Ce code s'exécute sur le principal (thread d'interface utilisateur). Cela verrouille l'interface utilisateur jusqu'à ce que le code soit exécuté. Ainsi, l'interface utilisateur ne peut pas se mettre à jour tant que votre code n'est pas terminé. Cela signifie que l'interface utilisateur n'affichera pas la mise à jour de votre propriété tant que votre code ne sera pas exécuté. Pour mettre à jour l'interface utilisateur pendant que votre code est en cours d'exécution, vous devez exécuter votre code dans un BackgroundWorker ou une tâche asynchrone.


3 Réponses :


3
votes

Avec Thread.Sleep, vous bloquez votre interface graphique. Essayez d'utiliser une minuterie pour vos besoins. Une minuterie fonctionnera simultanément sur votre thread GUI et ne le gèlera donc pas. Vous devrez également implémenter l'événement PropertyChanged pour votre compteur Assurez-vous également de définir votre DataContext

    //create a dependency property you can bind to (put into class)
    public int Counter
    {
        get { return (int)this.GetValue(CounterProperty); }
        set { this.SetValue(CounterProperty, value); }
    }

    public static readonly DependencyProperty CounterProperty =
        DependencyProperty.Register(nameof(Counter), typeof(int), typeof(MainWindow), new PropertyMetadata(default(int)));


    //Create a timer that runs one second and decreases CountDown when elapsed (Put into click event)
    Timer t = new Timer();
    t.Interval = 1000;
    t.Elapsed += CountDown;
    t.Start();

    //restart countdown when value greater one (put into class)
    private void CountDown(object sender, ElapsedEventArgs e)
    {
        if (counter > 1)
        {
            (sender as Timer).Start();
        }
        Counter--;
    }


0 commentaires

0
votes

Vous pouvez utiliser async await pour introduire un délai léger.

Son principal avantage par rapport à une minuterie est qu'il n'y a aucun risque de laisser le délégué accroché et en cours d'exécution.

Dans ce modèle de vue, j'utilise mvvmlight, mais n'importe quelle implémentation d'ICommand ferait l'affaire.

<Grid>
    <StackPanel>
    <TextBlock Text="{Binding Counter}"/>
        <Button Content="Count" Command="{Binding CountDownCommand}"/>
    </StackPanel>
</Grid>

Pas grand chose à voir, elle se lie à Counter, bien sûr:

 …..
using System.Threading.Tasks;
using GalaSoft.MvvmLight.CommandWpf;
namespace wpf_99
{
public class MainWindowViewModel : BaseViewModel
{
    private int counter =10;

    public int Counter
    {
        get { return counter; }
        set { counter = value; RaisePropertyChanged(); }
    }

    private RelayCommand countDownCommand;
    public RelayCommand CountDownCommand
    {
        get
        {
            return countDownCommand
            ?? (countDownCommand = new RelayCommand(
             async () =>
             {
                 for (int i = 10; i > 0; i--)
                 {
                     await Task.Delay(1000);
                     Counter = i;
                 }
             }
             ));
        }
    }

p>


0 commentaires

0
votes

Vous pouvez également exécuter Counter dans un thread distinct

Task.Run(() =>
             {
                 for (int i = 10; i > 0; i--)
                 {
                     Counter = i;
                     Thread.Sleep(1000);
                 }
             });


0 commentaires