IAsyncAction和IAsyncOperation接口

Windows 8 Store编程中常见的两个异步接口IAsyncActionIAsyncOperation都是从IAsyncInfo继承,分别用于没有返回值和有返回值的场合,还分别提供了带有进度的版本IAsyncActionWithProgressIAsyncOperationWithProgress开始我以为concurrency::create_task是一个类似于CreateThread一样的函数,后来MessageDialog::ShowAsync()让我意识到线程应该是创建于Async方法中,于是写个简单的Project测试一下,以增强了解。

新建一个空白XAML工程,在MainPage.xaml中添加一个按钮,Click处理函数中加上如下代码:

//openOperation是MainPage类的一个Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^类型成员变量,初始化为nullptr
if(openOperation == nullptr)
{
  Windows::Storage::Pickers::FileOpenPicker^ openPicker = ref new Windows::Storage::Pickers::FileOpenPicker();
  openPicker->ViewMode = Windows::Storage::Pickers::PickerViewMode::Thumbnail;
  openPicker->SuggestedStartLocation = Windows::Storage::Pickers::PickerLocationId::PicturesLibrary;
  openPicker->FileTypeFilter->Append(".png");
  openOperation = openPicker->PickSingleFileAsync();
}
else
{
  openOperation->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Storage::StorageFile^>([this](Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ asyncInfo, Windows::Foundation::AsyncStatus asyncStatus)
  {
    if(asyncStatus == Windows::Foundation::AsyncStatus::Completed)
    {
      Windows::Storage::StorageFile^ file = asyncInfo->GetResults();
      Windows::UI::Core::DispatchedHandler^ handler = ref new Windows::UI::Core::DispatchedHandler([this, file]()
      {
        if(file != nullptr)
        {
          this->Frame->Navigate(TypeName(ViewPage::typeid), safe_cast<Object^>(file));
        }
        else
        {
          Windows::UI::Popups::MessageDialog^ msgDlg = ref new Windows::UI::Popups::MessageDialog("Can't open this file.");
          msgDlg->ShowAsync();
        }
      });
      Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, handler);
    }
  });
}
这里为什么要写一个如此别扭的逻辑,就是为了要测试一下IAsyncOperation接口的Completed属性,作为经常使用CreateThread函数的VC程序员,不知你是否会这样想,当调用Async类型的函数后,异步操作已经在另一个线程中启动了,这个时候我们再从当前线程里为Completed属性指定一个Handler,这样安全吗?就能确保当前线程不会在此处被中断?还是这里面另有别的玄机?所以我们就尽可能的滞后添加Handler,看看会有什么故事。

新添加一个空白XAML页名为ViewPage.xaml,拖放一个Image控件,x:Name="imageShow",OnNavigatedTo函数中添加如下代码:

Windows::Storage::StorageFile^ file = safe_cast<Windows::Storage::StorageFile^>(e->Parameter);
if(file)
{
  auto openOp = file->OpenAsync(Windows::Storage::FileAccessMode::Read);
  openOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Storage::Streams::IRandomAccessStream^>([this](Windows::Foundation::IAsyncOperation<Windows::Storage::Streams::IRandomAccessStream^>^ asyncInfo, Windows::Foundation::AsyncStatus asyncStatus)
  {
    if(asyncStatus == Windows::Foundation::AsyncStatus::Completed)
    {
      Windows::Storage::Streams::IRandomAccessStream^ stream = asyncInfo->GetResults();
      Windows::UI::Core::DispatchedHandler^ handler = ref new Windows::UI::Core::DispatchedHandler([this, stream]()
      {
        Windows::UI::Xaml::Media::Imaging::BitmapImage^ bmp = ref new Windows::UI::Xaml::Media::Imaging::BitmapImage;
        auto setOp = bmp->SetSourceAsync(stream);
        setOp->Completed = ref new Windows::Foundation::AsyncActionCompletedHandler([this, bmp](Windows::Foundation::IAsyncAction^ asyncInfo, Windows::Foundation::AsyncStatus asyncStatus)
        {
          if(asyncStatus == Windows::Foundation::AsyncStatus::Completed)
          {
            Windows::UI::Core::DispatchedHandler^ handler = ref new Windows::UI::Core::DispatchedHandler([this, bmp]()
            {
              imageShow->Source = bmp;
            });
            Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, handler);
          }
        });
      });
      Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, handler);
    }
  });
}

不得不说,lambda表达式确实是个好东西。现在,编译你的Project,然后调试运行,在MainPage里,单击按钮,选择一张图片,然后程序再次显示MainPage,好像什么都没有做,然后你可以去喝杯水或者吃个苹果,等到你回来后,再次单击刚才那个按钮,一切正常的话,你会发现程序导航到了ViewPage并且显示了刚才你选择的那张图片。

经多次测试发现,无论多久之后再添加Completed Handler,程序都可以顺利执行,而且值得注意的是只可以添加一次,再次改动就会造成异常。

看看代码,你会怎么想?事到如今,不妨想当然一下,Async线程中是不是存在一个类似于事件对象的东西,初始是Reset状态,当线程完成工作后就等待在此处,当你改动Completed属性时,set方法调用了SetEvent函数(这或许就是Completed是一个property而非一个event的原因?),然后Async线程得以继续到你指定的Handler中去执行,这时已是时过境迁,再次改动Completed属性当然不合理,所以要抛出异常。

没有找到官方说明,完全属于推测,或有疏漏之处,望不吝指正。

posted on 2012-12-06 16:02  孤影对酌  阅读(2444)  评论(0编辑  收藏  举报

导航