C# 如何在例程中使用MVVM更新UI中的属性
我想建造一些倒计时计数器。问题是,我的解决方案仅显示10秒后的起始值10和最后值1。当然,我已经实现了INotifyPropertyChanged接口。对此解决方案有何建议C# 如何在例程中使用MVVM更新UI中的属性,c#,wpf,C#,Wpf,我想建造一些倒计时计数器。问题是,我的解决方案仅显示10秒后的起始值10和最后值1。当然,我已经实现了INotifyPropertyChanged接口。对此解决方案有何建议 <Button Content="Generuj" Command="{Binding ButtonStart}"></Button> <TextBox Text="{Binding Counter, Mode=OneWay}"></TextBox> private vo
<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;
}
}
专用空心按钮开始单击(对象对象对象)
{
对于(int i=10;i>0;i--)
{
系统线程线程睡眠(1000);
计数器=i;
}
}
使用线程。睡眠您正在冻结GUI。试着用一个定时器来达到你的目的。
计时器将同时运行到GUI线程,因此不会冻结它。
此外,还需要为计数器实现PropertyChanged事件
还要确保设置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--;
}
您可以使用async await引入轻量级延迟 与计时器相比,它的主要优点是不存在让代理挂接并运行的风险 在这个视图模型中,我使用mvvmlight,但ICommand的任何实现都可以
…..
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;
}
}
));
}
}
这与观点不太相符,当然,这与反观点有关:
<Grid>
<StackPanel>
<TextBlock Text="{Binding Counter}"/>
<Button Content="Count" Command="{Binding CountDownCommand}"/>
</StackPanel>
</Grid>
您也可以在单独的线程中运行计数器
Task.Run(() =>
{
for (int i = 10; i > 0; i--)
{
Counter = i;
Thread.Sleep(1000);
}
});
计数器必须是属性,必须实现INotifyPropertyChanged。睡眠(1000);从GUI线程运行->这将阻止对GUI的更新。您将注意到10秒钟的睡眠,然后计数器被设置为0。您已经通过单击按钮开始运行代码。此代码在主(UI线程)上运行。这将锁定UI,直到代码运行完毕。因此,在代码完成之前,UI无法更新。这意味着在代码完成运行之前,UI不会显示您的属性更新。要在代码运行时更新UI,需要在BackgroundWorker或异步任务中运行代码。