我正在使用MVVM Light构建一个WP7 (Windows Phone7)应用程序。我希望由模型执行的所有工作都在后台线程上运行。然后,当工作完成时,引发一个事件,以便ViewModel可以处理数据。
我已经发现,我不能从WP7应用程序异步调用委托。
目前,我正在尝试使用ThreadPool.QueueUserWorkItem()在后台线程上运行一些代码,并使用MVVM Light的DispatcherHelper.CheckBeginInvodeOnUI()在UI线程上引发一个事件,向ViewModel发出数据已加载的信号(当VS2010和Blend 4试图显示设计时视图时,这会导致它们崩溃)。
是否有任何示例代码可以在后台线程上运行一些代码,然后将事件分派回WP7应用程序的UI线程?
提前谢谢你,杰夫。
编辑-这是一个示例模型
public class DataModel
{
public event EventHandler<DataLoadingEventArgs> DataLoadingComplete;
public event EventHandler<DataLoadingErrorEventArgs> DataLoadingError;
List<Data> _dataCasch = new List<Data>();
public void GetData()
{
ThreadPool.QueueUserWorkItem(func =>
{
try
{
LoadData();
if (DataLoadingComplete != null)
{
//Dispatch complete event back to the UI thread
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
//raise event
DataLoadingComplete(this, new DataLoadingEventArgs(_dataCasch));
});
}
}
catch (Exception ex)
{
if (DataLoadingError != null)
{
//Dispatch error event back to the UI thread
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
//raise error
DataLoadingError(this, new DataLoadingErrorEventArgs(ex));
});
}
}
});
}
private void LoadData()
{
//Do work to load data....
}
}发布于 2010-07-22 04:52:41
下面是我如何解决这个问题的方法。
您的ViewModel实现了INotifyPropertyChanged,对吗?没有必要分派事件。只需在模型中将它们提升为“空的”,然后在ViewModel中分派RaisePropertyChanged。
是的,您的代码中应该包含某种类型的单例模型/数据库。毕竟,如果不是一些巨大的单例数据库,那么SQL数据库又是什么呢?因为我们在WP7中没有数据库,所以不要害怕创建一个单例对象。我有一个名为"Database“的数据库:)
我刚刚尝试将我的数据加载线程化,并意识到实际上最好的方法就是直接在模型级别上实现INotifyPropertyChanged。There's no shame in this。
因此,考虑到这一点,我在单例数据库对象中执行以下操作来加载和返回我的Tour“表”(请注意thread.sleep,使其加载所需的时间可见,通常不超过100ms)。数据库类现在实现了INotifyPropertyChanged,并在加载完成时引发事件:
public ObservableCollection<Tour> Tours
{
get
{
if ( _tours == null )
{
_tours = new ObservableCollection<Tour>();
ThreadPool.QueueUserWorkItem(LoadTours);
}
return _tours;
}
}
private void LoadTours(object o)
{
var start = DateTime.Now;
//simlate lots of work
Thread.Sleep(5000);
_tours = IsoStore.Deserialize<ObservableCollection<Tour>>( ToursFilename ) ?? new ObservableCollection<Tour>();
Debug.WriteLine( "Deserialize time: " + DateTime.Now.Subtract( start ).ToString() );
RaisePropertyChanged("Tours");
}你明白了吗?我在后台线程上反序列化Tour列表,然后引发一个propertychanged _ raising事件。
现在在ViewModel中,我想要一个要绑定到的TourViewModels列表,一旦看到Tours表发生了变化,我就用linq查询选择它。在ViewModel中监听数据库事件可能有点便宜--将其封装在模型中可能“更好”,但让我们不要做我们不需要的工作,嗯?
在Viewmodel的构造函数中挂钩Database事件:
public TourViewModel()
{
Database.Instance.PropertyChanged += DatabasePropertyChanged;
}监听适当的表更改(我们喜欢魔术字符串!;-) ):
private void DatabasePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "Tours")
{
LoadTourList();
}
}从表中选择我想要的记录,然后告诉视图有新数据:
public void LoadTourList()
{
AllTours = ( from t in Database.Instance.Tours
select new TourViewModel( t ) ).ToList();
RaisePropertyChanged( "AllTours" );
}最后,在您的ViewModelBase中,最好检查您的RaisePropertyChanged是否需要调度。我的"SafeDispatch“方法与MVVMlight中的方法几乎相同:
private void RaisePropertyChanged(string property)
{
if ( PropertyChanged != null )
{
UiHelper.SafeDispatch(() =>
PropertyChanged(this, new PropertyChangedEventArgs(property)));
}
}这在我的代码中工作得很好,而且我认为它相当整洁?
最后,对于专家的额外提示:在WP7中,在页面中添加一个带有IsIndeterminate=True的ProgressBar可能会更好--这将显示“虚线”进度条。然后,当ViewModel第一次加载时,您可以将"ProgressBarVisible“属性设置为Visible (并引发相关的PropertyChanged事件)。将ProgressBar的可见性绑定到此ViewModel属性。当数据库PropertyChanged事件触发时,将可见性设置为折叠,以使进度条消失。
这样,当反序列化运行时,用户将在其屏幕顶部看到"IsIndeterminate“进度条。好的!
发布于 2010-07-21 03:41:41
我以前没有为WP7开发过,但我找到了this article that might be useful!
以下是本文中的Dining Philosopher示例代码,它可以让您很好地了解如何从另一个线程向UI引发事件:
public DinnersViewModel(IDinnerCatalog catalog)
{
theCatalog = catalog;
theCatalog.DinnerLoadingComplete +=
new EventHandler<DinnerLoadingEventArgs>(
Dinners_DinnerLoadingComplete);
}
public void LoadDinners()
{
theCatalog.GetDinners();
}
void Dinners_DinnerLoadingComplete(
object sender, DinnerLoadingEventArgs e)
{
// Fire Event on UI Thread
View.Dispatcher.BeginInvoke(() =>
{
// Clear the list
theDinners.Clear();
// Add the new Dinners
foreach (Dinner d in e.Results)
theDinners.Add(d);
if (LoadComplete != null)
LoadComplete(this, null);
});
}我希望它能对您有所帮助:)。
有一件事让人困惑:你说当你使用帮助器来引发事件时,VS2010就会崩溃……当它崩溃的时候,你到底看到了什么?你是不是遇到了异常?
发布于 2010-09-09 04:52:12
杰夫,我自己还在想这件事。我发布了一个类似的问题,并通过构建一个简单的样本来亲自回答。这里:
A super-simple MVVM-Light WP7 sample?
1)我从ViewModelBase派生了我的模型(是的,我的模型)。这为我提供了Mvvm-Light的消息传递和INotifyPropertyChanged实现,这很方便。你可能会说这不是“纯粹的”,但我认为这无关紧要。
2)我和你一样使用了Mvvm-Light DispatcherHelper.CheckBeginInvokeOnUIhelper (来自我的模型,而不是我的ViewModel)。
希望这能有所帮助。
https://stackoverflow.com/questions/3293137
复制相似问题