有一些方法可以使用 SynchronizationContext 从另一个线程修改视图。
请看这个例子:
private void Button_Click(object sender, RoutedEventArgs e)
{
var sync = SynchronizationContext.Current;
BackgroundWorker w = new BackgroundWorker();
w.DoWork+=(_, __)=>
{
//sync.Post(p => { button.Content = "Working"; }, null);
int j = 0;
for (int i = 0; i < 10; i++)
{
j++;
sync.Post(p => { button.Content = j.ToString(); }, null);
Thread.Sleep(1000);
}
sync.Post(p => { button.Background = Brushes.Aqua; button.Content = "Some Content"; }, null);
};
w.RunWorkerAsync();
}
这就是视图:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="button" Content="Some Content" Click="Button_Click"/>
</Grid>
</Window>
此代码多次更新视图(在本例中为按钮)。我认为这解决了你最初的问题。
- - 编辑 - -
这是使用这个想法的更好方法:我建议在基本视图模型中创建这样的方法:
public void LockAndDoInBackground(Action action, string text, Action beforeVisualAction = null, Action afterVisualAction = null)
{
if (IsBusy)
return;
var currentSyncContext = SynchronizationContext.Current;
ActiveThread = new Thread((_) =>
{
currentSyncContext.Send(t =>
{
IsBusy = true;
BusyText = string.IsNullOrEmpty(text) ? "Wait please..." : text;
if (beforeVisualAction != null)
beforeVisualAction();
}, null);
action();
currentSyncContext.Send(t =>
{
IsBusy = false;
BusyText = "";
if (afterVisualAction != null)
afterVisualAction();
}, null);
});
ActiveThread.Start();
}
这样任何子视图模型都可以使用它来执行大量数据处理,并且 UI 不会被冻结。IsBusy
and BusyText
是绑定到视图等待消息和等待元素的可见性的视图模型变量。
这是在子视图模型命令中使用的示例:
private RelayCommand _SomeCommand;
public RelayCommand SomeCommand
{
get { return _SomeCommand ?? (_SomeCommand = new RelayCommand(ExecuteSomeCommand, CanExecuteSomeCommand)); }
}
private void ExecuteSomeCommand()
{
Action t = ()=>
{
//some action
};
LockAndDoInBackground(t, "Generating Information...");
}
private bool CanExecuteSomeCommand()
{
return SelectedItem != null;
}
希望这将成为一个更清晰的例子。