我有一个标签,我想在每秒钟后更新它的内容,3秒钟后我只看到最后一个字符串"Step 3…"我做错了什么?如果出于某种原因我不能使用Thread.Sleep():
视图:
<Window x:Class="WpfApplication1.ScrollerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Scroller" DataContext="{StaticResource scrollerVM}" Height="150" Width="300">
<Grid>
<ListBox ItemsSource="{Binding Messages}" Width="200" Height="50" BorderThickness="0" VerticalAlignment="Top" HorizontalAlignment="Left">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Text}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
<Button Width="70" Height="24" Content="Add new" Command="{Binding AddNew}" HorizontalAlignment="Left" Margin="0,56,0,30" />
</Grid>
</Window>
查看模型:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
namespace WpfApplication1.Scroller
{
public class Message
{
public Message(string _text)
{
text = _text;
}
private string text;
public string Text
{
get { return text; }
set {text = value;}
}
}
public class ScrollerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public DelegateCommand AddNew { get; protected set; }
ObservableCollection<Message> _messages = new ObservableCollection<Message>();
public ObservableCollection<Message> Messages
{
get { return _messages; }
set
{
_messages = value;
OnPropertyChanged("Messages");
}
}
public ScrollerViewModel()
{
AddNew = new DelegateCommand(Add);
}
private void Add(object parameter)
{
UpdateProgress("Step 1...");
UpdateProgress("Step 2...");
UpdateProgress("Step 3...");
}
private void UpdateProgress(string step)
{
Messages.Clear();
Messages.Add(new Message(step));
Thread.Sleep(1000);
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
这是因为您正在UI线程中睡觉。在"添加"完成之前,用户界面将没有机会更新。您可以使用带有ReportProgress的BackgroundWorker来实现您想要的目标。类似这样的东西:
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
worker.ReportProgress(1, "Step1");
Thread.Sleep(1000);
worker.ReportProgress(2, "Step2");
Thread.Sleep(1000);
worker.ReportProgress(3, "Step3");
};
worker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
{
string step = (string)args.UserState;
Messages.Clear();
Messages.Add(new Message(step));
};
worker.RunWorkerAsync();
执行DoWork
时,UI线程不会被占用,但ProgressChanged
中的代码将在UI线程上执行。
您永远不应该调用Thread.Sleep当您在UI线程上时。这将阻止Dispatcher,并且不会进行渲染。绑定更新等。
如果您想在UpdateProgress()调用之间等待,请使用DispatcherTimer。
在添加新消息之前,您正在清除这些消息。
private void UpdateProgress(string step)
{
Messages.Clear(); // <- Why?
Messages.Add(new Message(step));
Thread.Sleep(1000);
}