我遇到这种情况:
我想在MainWindow的ViewModel中加载一个集合,我有一个大数据,所以当我进入人物集合的幻灯片时,它应该等待完成加载然后我可以看到完整的列表,我有以下内容:< / p>
:
<ListView .....
ItemsSource{Binding PeopleList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
... />
在视图模式中我有:
// ...
private ObservableCollection<Person> _People;
public ObservableCollection<Person> People
{ get{return _People;} set{ _People = value; RaisePropertyChange("People");}}
// ...
并且我想在加载第一个完全开始加载第二个...之后逐个加载所有人列表而不阻止主窗口我希望我的窗口看起来像:
我厌倦了这样做,但我失败了。谢谢。
答案 0 :(得分:2)
存在使用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>
此代码会多次更新视图(在本例中为按钮)。我认为这可以解决你的初步问题。
<强> ---- ---- EDIT 强>
这是使用这个想法的更好方法:我建议在基本视图模型中创建这样的方法:
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
和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;
}
希望这将成为一个更明确的例子。
答案 1 :(得分:1)
我会这样做:
IsLoading
标志添加到项目DataTemplate
应检查该标志,并为
IsLoading=true
它应该显示一些重大进展,否则
真实数据IsLoading = TRUE
将空项对象添加到ObservableCollection,
然后开始在另一个线程上检索项目数据IsLoading = FALSE
答案 2 :(得分:0)
您有两种方法可以实现您想要的方案:
使用 BackgroundWorker 并实施它。如果您想将其与进度一起使用,ProgressChanged
将是合适的。 DoWork
将是您数据的重载。 CompletedEvent
是您完成该任务的结果。
使用 TPL ,您可以立即开始使用Task.Factory.StartNew()
并将操作设为
你的数据加载。其中一个是构造函数,您可以传递TaskScheduler.FromCurrentSynchronizationContext()
,以便它可以将其编组到UI Dispatcher
。