2016-12-03 80 views
0

我想为通用Windows项目使用MVVM,但存储文件的接口抱怨了很多关于使用异步。下面的代码,有时作品:ValueConverter for StorageFile =>图像

public object Convert(object value, Type targetType, object parameter, string language) 
    { 
     var storageFile = value as StorageFile; 
     return GetImageAsync(storageFile).Result; 
    } 

    private static async Task<ImageSource> GetImageAsync(StorageFile storageFile) 
    { 
     var bitmapImage = new BitmapImage(); 
     var stream = await storageFile.OpenAsync(FileAccessMode.Read).AsTask().ConfigureAwait(false); 
     bitmapImage.SetSource(stream); 
     return bitmapImage; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, string language) 
    { 
     return null; 
    } 
} 

直到我选择一个新的图像加载,然后我得到了错误“{”的应用程序调用这是编组为一个不同的线程的接口。 (异常来自HRESULT:0x8001010E(RPC_E_WRONG_THREAD)) “}”

所以我试图改变它时使用的每另一个线程CoreDispatcher:

public class FileToImageConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, string language) 
    { 
     var storageFile = value as StorageFile; 
     Task<ImageSource> image = null; 
     Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() => 
     { 
      image = GetImageAsync(storageFile); 
      image.RunSynchronously(); 
     }); 

     return image.Result; 
    } 

    private static async Task<ImageSource> GetImageAsync(StorageFile storageFile) 
    { 
     var bitmapImage = new BitmapImage(); 
     var stream = await storageFile.OpenAsync(FileAccessMode.Read).AsTask().ConfigureAwait(false); 
     bitmapImage.SetSource(stream); 
     return bitmapImage; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, string language) 
    { 
     return null; 
    } 
} 

的NullReferenceException上的BitmapImage。这对我来说绝对有意义 - 异步调度器将控制权交给父进程,图像尚未分配,空引用异常。但我不知道什么是正确的方法!

+1

一个值转换器不应该返回一个UIElement。你为什么觉得你需要这样的事? – Clemens

+0

我想要获取潜在的大型图像文件并将它们显示在应用程序中,提供关于它们的像素/摄影信息,所以我不想冻结等待文件加载的UI。 –

+0

不过,转换器应该返回一个ImageSource(例如BitmapImage),而不是Image控件。 – Clemens

回答

0

谢谢Clemens您对OP的评论,这让我意识到我是模式痴迷并专注于使用我喜欢的东西而不是做正确的设计。

这是造成这个问题的来源是这样的:

private async void GetFile() 
    { 
     var filePicker = new FileOpenPicker(); 
     filePicker.FileTypeFilter.Add(".jpg"); 
     filePicker.FileTypeFilter.Add(".png"); 
     filePicker.FileTypeFilter.Add(".gif"); 
     filePicker.FileTypeFilter.Add(".bmp"); 
     filePicker.ViewMode = PickerViewMode.Thumbnail; 
     filePicker.SuggestedStartLocation = PickerLocationId.Desktop; 
     filePicker.CommitButtonText = "Open"; 
     CurrentFile = await filePicker.PickSingleFileAsync(); //Bad code used CurrentFile set and NotifyPropertyChanged to start up the value converter code from OP 

     //New, obvious better code    
     CurrentImage = await GetImageSource(CurrentFile); 

     var statistics = new ImageStatistics(); 

     Logger.Log("Metadata start"); 
     var data = statistics.GetMetaData(CurrentFile); 

     Logger.Log("Color Counts start"); 
     var colorCounts = statistics.GetColorCounts(CurrentFile); 

     var filterer = new ColorFilterer(); 
     Logger.Log("Color Counts await start"); 
     var filteredColors = filterer.GetTopColors(await colorCounts, 10); 
     Logger.Log("Color Counts await end"); 

     Logger.Log("Metadata await start"); 
     var metaData = await data; 
     Logger.Log("Metadata await end"); 

     Make = metaData[SystemProperty.CameraManufacturer]; 
     Model = metaData[SystemProperty.CameraModel]; 
     ExposureTime = string.Format("1/{0}",1/Convert.ToDouble(metaData[SystemProperty.ExposureTime])); 
     ISOSpeed = metaData[SystemProperty.ISOSpeed]; 
     FStop = string.Format("f/{0}", metaData[SystemProperty.FStop]); 
     ExposureBias = metaData[SystemProperty.ExposureBias]; 

     TopColors = filteredColors.Select(pair => new ColorStatistics { Color = pair.Key, Count = pair.Value }).ToList(); 
    } 

所以我只是继续执行,我在图像上希望它被选中后的操作。这里还有很多需要解决的问题,特别是因为我在执行工作时阻止UI,而不是通过订阅这些其他UI组件来将这些操作委托给该属性,但这是一个开始,没有更多的例外!

请注意,此处未包括,值转换器已从主应用程序层中删除。