在Windows Phone 7中,对封装在TaskEx中的Linq-To-SQL的异步调用有时不会返回

本文关键字:调用 异步 返回 Linq-To-SQL 中的 Phone Windows 封装 TaskEx | 更新日期: 2023-09-27 18:15:53

我使用Linq-To-SQL封装在TaskEx.Run中对数据库进行了大量调用,以便我可以返回UI并显示一些加载图形。它加载一些数据到ViewModel。

它在第一次被触发时工作,但通常在第三次(尽管有时更多)它被触发时,它永远不会完成,好像它所在的线程"丢失"了,或者调度程序永远不会再次执行它——没有引发异常。

如果我激活UI使代码再次运行,那么它将再次工作三次左右。

我已经使用了调试器,它通常会通过延续代码的一部分,然后执行跟踪消失。

这是一个使用Microsoft.Bcl.Async库的Windows Phone 7.5项目。

下面是代码,

public async Task LoadConversionsPageDataAsyncTask(int profileId, ConversionId conversionId)
    {
        // Fire the event off
        this.IsConversionDataLoading = true;
        if (this.ConversionDataLoading != null)
            this.ConversionDataLoading(this);
        // Load up the data in case of tombstone situation
        if (App.VM.SelectedProfile == null || App.VM.SelectedProfile.Id != profileId)
            App.VM.SelectedProfile = (from Profile p in App.VM.appDB.Profiles where p.Id == profileId select p).FirstOrDefault();
        if (App.VM.SelectedConversionType != conversionId) 
            App.VM.SelectedConversionType = conversionId;

        // TODO: If gender not specified, then return Female measurements. Note only perform gener query on tables that have 
        // Gender fields (even after casting) because it still generate SQL to query gender
        GenderId qGender = (this.SelectedProfile.Gender == GenderId.Unspecified) ? GenderId.Female : this.SelectedProfile.Gender;
        this.LoadRequiredMeasurements(qGender, this.SelectedConversionType);
        Dictionary<MeasurementId, double> measuredVals = this.ConversionMeasurements.ToDictionary(k => k.MeasurementId, v => Double.Parse(v.Value));
        // Check we have all the necessary measurements
        if (measuredVals == null) return;
        // Build up by regions
        RegionId selectedRegion = this.SelectedRegion;
        this.GroupedConversions = await TaskEx.Run(() =>
        {
            // Do database (Linq-to-sql) stuff first, so this should translate to SQL and run SQL with AsList
            List<ConversionData> conversions = (from d in conversiondsDB.ConversionData
                                                where d is ConversionData
                                                    // Filter to specific region, gender, conversion
                                                && d.Region == selectedRegion
                                                && d.Gender == qGender
                                                && d.Conversion == this.SelectedConversionType
                                                && !this.BlacklistedBrands.Contains(d.Brand)
                                                select d).ToList();
            conversions.Sort((a, b) => { return a.BrandName.CompareTo(b.BrandName); });
            // Group up the brand names
            string groupKeys = "#abcdefghijklmnopqrstuvwxyz";
            // Initially store in a dictionary
            Dictionary<string, List<ConversionData>> groupDict = new Dictionary<string, List<ConversionData>>();
            foreach (char c in groupKeys)
            {
                groupDict.Add(c.ToString(), new List<ConversionData>());
            }
            foreach (ConversionData cd in conversions)
            {
                // Find the best fit whilst at it
                cd.FindBestFit(measuredVals);
                // Add to the right group according to the first letter of the brand name
                char key = char.ToLower(cd.BrandName[0]);
                if (key < 'a' || key > 'z') key = '#';
                groupDict[key.ToString()].Add(cd);
            }
            // Buffer first to avoid triggering the NotifyPropertyChanged events on ObservableCollection hundreds of times
            List<LongListSelectorGroup<ConversionData>> buff = new List<LongListSelectorGroup<ConversionData>>();
            foreach (char key in groupKeys)
            {
                string k = key.ToString();
                buff.Add(new LongListSelectorGroup<ConversionData>(k, groupDict[k]));
            }
            return new ObservableCollection<LongListSelectorGroup<ConversionData>>(buff);
        });
        // Fire the end event
        if (this.ConversionDataLoaded != null)
            this.ConversionDataLoaded(this);
        this.IsConversionDataLoading = false;
    }

以下是OnNavigatedTo事件的主叫代码

protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        this.AdRotatorControl.Invalidate();
        base.OnNavigatedTo(e);

        // Load up the data using a query string in case of tombstoning
        string profileIdStr, conversionIdStr;
        NavigationContext.QueryString.TryGetValue("ProfileId", out profileIdStr);
        int profileId = System.Int32.Parse(profileIdStr);
        NavigationContext.QueryString.TryGetValue("ConversionId", out conversionIdStr);
        ConversionId conversionId = (ConversionId)Enum.Parse(typeof(ConversionId), conversionIdStr, true);
        if (App.VM.GroupedConversions == null
            || !App.VM.SkipLoadConversionPageData)
        {
            App.VM.LoadConversionsPageDataAsyncTask(profileId, conversionId);
        }
        if (App.VM.SkipLoadConversionPageData)
            App.VM.SkipLoadConversionPageData = false;
    }

在Windows Phone 7中,对封装在TaskEx中的Linq-To-SQL的异步调用有时不会返回

由于您从未await LoadConversionsPageDataAsyncTask返回的Task,因此您永远不会观察到它的异常。修改OnNavigatedTo为:

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    this.AdRotatorControl.Invalidate();
    base.OnNavigatedTo(e);
    // Load up the data using a query string in case of tombstoning
    string profileIdStr, conversionIdStr;
    NavigationContext.QueryString.TryGetValue("ProfileId", out profileIdStr);
    int profileId = System.Int32.Parse(profileIdStr);
    NavigationContext.QueryString.TryGetValue("ConversionId", out conversionIdStr);
    ConversionId conversionId = (ConversionId)Enum.Parse(typeof(ConversionId), conversionIdStr, true);
    if (App.VM.GroupedConversions == null
        || !App.VM.SkipLoadConversionPageData)
    {
        await App.VM.LoadConversionsPageDataAsyncTask(profileId, conversionId);
    }
    if (App.VM.SkipLoadConversionPageData)
        App.VM.SkipLoadConversionPageData = false;
}

试试,看看你现在是否观察到一个异常