简体   繁体   中英

How to update property in UI using MVVM in routine

I want to build some count down counter. The problem is that my solution display only beginning value 10 and last value 1 after 10 sec. Of course, I've implemented the INotifyPropertyChanged interface. Any suggestions for that 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;
    }
}

With Thread.Sleep you are freezing your GUI. Try using a Timer for your purpose. A timer will run simultaneously to your GUI thread and thus will not freeze it. Also you will need to implement the PropertyChanged Event for your counter Also make sure to set your 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--;
    }

You can use async await to introduce a lightweight delay.

It's main advantage over a timer is there's no risk of leaving the delegate hooked and running.

In this viewmodel I use mvvmlight, but any implementation of ICommand would do.

 …..
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;
                 }
             }
             ));
        }
    }

Not much to the view, it binds to Counter, of course:

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

You can also run Counter in separate Thread

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM