在Windows Phone上同步加载图像的更好方法?

时间:2012-12-06 16:30:45

标签: c# windows-phone-7 windows-phone

我是新手做C#Windows Phone编程。

简而言之,我目前正在构建一个应用程序:

加载image A

加载image B

然后加载image C

然后使用这3张图片进行一些后期处理。

我的图像B和图像C在项目中构建为Content。 图像A从图库中选择或通过相机拍摄,或者我们可以简单地假设图像A是从隔离存储加载的。

我遇到了一个问题,我认为这是由异步图像加载引起的。

这是我的代码:

...
// I intend to load the 3 pictures by calling the method: LoadImage(int id) and LoadCImage();

            else if (ListBox.SelectedIndex == 0)
            {
                Debug.WriteLine("Selected 0");
                PhotoProcessor pp = new PhotoProcessor();
                WriteableBitmap imageA = new WriteableBitmap(AImage);
                WriteableBitmap imageB = LoadImage(0);
                WriteableBitmap imageC = LoadCImage();
                WriteableBitmap mix = pp.Mix(pp.CalcAverageColour(0), imageA, imageB, imageC);
                resultPic.Source = mix;
            }
...

private WriteableBitmap LoadImage(int id)
        {
            //String uriString = "/Assets/img0.jpg";            
            //BitmapImage img = new BitmapImage(new Uri(uriString, UriKind.Relative));
            BitmapImage img = new BitmapImage();
            img.CreateOptions = BitmapCreateOptions.None;
            //img.SetSource(Application.GetResourceStream(new Uri("/Assets/facetemplate0.jpg", UriKind.Relative)).Stream);
            img.UriSource = new Uri("/Assets/img" + id + ".jpg", UriKind.Relative);

            //img.UriSource = new Uri(uriString, UriKind.Relative);
            return new WriteableBitmap(img);
        }

        private WriteableBitmap LoadCImage()
        {
            //BitmapImage img = new BitmapImage(new Uri("/Assets/imgC.jpg", UriKind.Relative));
            BitmapImage bmp = new BitmapImage();
            bmp.CreateOptions = BitmapCreateOptions.None;
            //img.SetSource(Application.GetResourceStream(new Uri("/Assets/imgC.jpg", UriKind.Relative)).Stream);
            bmp.UriSource = new Uri("/Assets/imgC.jpg", UriKind.Relative);
            return new WriteableBitmap(bmp);
        }

现在我的问题是:

当我尝试运行此代码时,它将抛出一个Null Reference Exception,这是因为函数mix无法加载Image AB和C(加载此图像是异步的)。

我想知道是否有办法让我按顺序加载这些图像然后让我将它们传递给mix函数?

我尝试了什么:

  1. 通过检查this great blog post,我可以知道有一些方法可以同步加载图像,但正如您在整个代码中看到的那样,我尝试使用SetSource(stream)像博客一样,但遗憾的是我得到了相同的Null Reference Exception。

  2. 我也考虑过EventHandler方法,但在这种情况下,我认为这不是一个好主意。如果我实现EventHandler,它会是(伪代码):

    imageA_Opened()
    {
    LoadImageB += imageB_Opened();
    }
    
    imageB_Opened()
    {
     LoadImageC += imageC_Opened();
    }
    
    imageC_Opened()
    {
    PhotoProcessor pp = new PhotoProcessor();
    pp.Mix(averageColour, A, B, C);
    }
    
  3. 我是对的吗?

2 个答案:

答案 0 :(得分:2)

Servy说你不应该用同步调用阻止UI是正确的。

话虽如此,我在WP7应用程序中有类似的要求。我使用“Async CTP”来添加编写同步函数的功能,这些函数在进行下一次调用之前一直等到它完成。我有API调用,要求早期调用的数据正常运行。

我相信这包含在.NET 4.5中,适用于WP8。

http://msdn.microsoft.com/en-ca/library/vstudio/hh191443.aspx

以下是我为我的应用提取数据的注意事项(请注意“异步”和“等待”关键字):

public async Task<bool> GetDefaultData()
{
    try
    {
        _cancellation = new CancellationTokenSource();

        UpdateProgress(DateTime.Now + ": Download Started.\n");
        List<string> data = await App._apiConnection.DoWorkAsync(_cancellation.Token, ApiInfo.GetBaseDataUriList());
        App._apiConnection.Done(data);

        UpdateProgress(DateTime.Now + ": Countries: " + App._context.Countries.Count() + "\n");
        UpdateProgress(DateTime.Now + ": Regions: " + App._context.Regions.Count() + "\n");
        UpdateProgress(DateTime.Now + ": Income Levels: " + App._context.IncomeLevels.Count() + "\n");
        UpdateProgress(DateTime.Now + ": Indicators: " + App._context.Indicators.Count() + "\n");

        data = await App._apiConnection.DoWorkAsync(_cancellation.Token, ApiInfo.GetCountryUriList("CA"));
        App._apiConnection.Done(data);
        UpdateProgress(DateTime.Now + ": CA Population: " + App._context.PopulationDatas.Count(c => c.Country.Iso2Code == "CA") + "\n");

        data = await App._apiConnection.DoWorkAsync(_cancellation.Token, ApiInfo.GetCountryUriList("US"));
        App._apiConnection.Done(data);
        UpdateProgress(DateTime.Now + ": US Population: " + App._context.PopulationDatas.Count(c => c.Country.Iso2Code == "US") + "\n");

        data = await App._apiConnection.DoWorkAsync(_cancellation.Token, ApiInfo.GetCountryUriList("CN"));
        App._apiConnection.Done(data);
        UpdateProgress(DateTime.Now + ": CN Population: " + App._context.PopulationDatas.Count(c => c.Country.Iso2Code == "CN") + "\n");

        return true;
    }
    catch (OperationCanceledException)
    {
        MessageBox.Show("Operation Cancelled");
        return false;



    }
    catch (Exception ex)
    {
        MessageBox.Show("getDefaultData Exception: " + ex.Message);

        return false;
    }
}

答案 1 :(得分:0)

假设 它肯定会更容易开发,是的,但它不会有效,因为你会长时间阻塞处理器,从而冻结你的应用程序。

  

我也考虑过EventHandler方法,但在这种情况下我不认为这是一个好主意。如果我实现EventHandler,它会是(伪代码):

是的,它会遵循你所描述的那种一般模式。这是解决此问题的适当方法。