0

我正在尝试将 MVVM 用于通用 Windows 项目,但存储文件的接口对使用异步有很多抱怨。以下代码有时有效:

    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。当然,这对我来说绝对有意义 - 异步调度程序将控制权交给父进程,尚未分配图像,空引用异常。但我不知道正确的方法是什么!

4

1 回答 1

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 组件订阅到属性来委派这些操作,但这是一个开始,不再有例外!

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

于 2016-12-04T17:30:01.510 回答