[英]How to run a function on a background thread for Windows Phone 7?
我正在使用MVVM Light来构建WP7(Windows Phone 7)应用程序。 我希望模型执行的所有工作都在后台线程上运行。 然后,完成工作后,引发一个事件,以便ViewModel可以处理数据。
我已经发现我无法从WP7应用程序异步调用委托。
目前我正在尝试使用ThreadPool.QueueUserWorkItem()在后台线程上运行一些代码,并使用MVVM Light的DispatcherHelper.CheckBeginInvodeOnUI()在UI线程上引发一个事件,以通知ViewModel数据已被加载(这会导致VS2010崩溃)和Blend 4在尝试显示设计时视图时)。
是否有任何示例代码在后台线程上运行某些代码,然后将事件调度回UI线程以获取WP7应用程序?
杰夫,先谢谢你。
编辑 - 这是一个示例模型
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....
}
}
以下是我如何解决这个问题的方法。
您的ViewModel实现了INotifyPropertyChanged吗? 没有必要发送活动。 只需在模型中“裸露”它们,然后在ViewModel中调度RaisePropertyChanged。
是的,你的代码中应该有一些单例模型/数据库。 毕竟,如果不是一些巨大的单身人士,什么是SQL数据库? 由于我们在WP7中没有数据库,所以不要害羞地创建单例对象。 我有一个名为“数据库”:)
我刚试过在那里线程化我的dataloads,并意识到实际上最好的方法就是在模型级别直接实现INotifyPropertyChanged。 这没有什么可耻的 。
所以,这就是我在单例数据库对象中所做的事情,以加载并返回我的Tours“表”(注意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事件。
现在在ViewModel中,我想要一个要绑定的TourViewModel列表,一旦我看到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属性。 触发Database PropertyChanged事件时,将可见性设置为Collapsed以使进度条消失。
这样,在反序列化运行时,用户将在其屏幕顶部看到“IsIndeterminate”进度条。 太好了!
我以前没有为WP7开发,但我发现这篇文章可能有用 !
这篇文章中的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会崩溃......当你崩溃时你究竟看到了什么? 你有例外吗?
杰夫,我还在自己搞这个东西。 我发布了一个类似的问题,最后通过构建一个简单的样本来回答它。 这里:
摘要是:
1)我从ViewModelBase
派生了我的模型(是的我的模型)。 这给了我Mvvm-Light的消息传递和INotifyPropertyChanged
的实现,这很方便。 你可以说这不是“纯粹的”,但我认为这不重要。
2)我使用Mvvm-Light DispatcherHelper.CheckBeginInvokeOnUI
帮助器(就像我的模型,而不是我的ViewModel)。
希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.