如何在 Windows 10 中创建使用异步和等待的转换器?

How to create a converter that use async and await in Windows 10?

我正在将我的 Windows Phone 8 ImageConverter 迁移到 Windows 10,但我在使用存储 API 时遇到问题,因为它使用异步和等待。有人可以建议可以用来实现我的要求吗?

我的WindowsPhone8图转换器class在下面

public class ImageConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            string imageUrl = value.ToString();

            if (imageUrl.Contains("NoImageIcon"))
                return value;

            if (imageUrl.Contains(Constants.IMAGES_FOLDER_PATH))
            {
                BitmapImage image = new BitmapImage();
                image.CreateOptions = BitmapCreateOptions.BackgroundCreation;

                IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();

                if (!myIsolatedStorage.FileExists(imageUrl)) return null;

                using (myIsolatedStorage)
                {
                    using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(imageUrl, FileMode.Open, FileAccess.Read))
                    {
                       image.SetSource(fileStream);
                    }
                }
                return image;
            }

            if (imageUrl.Contains("mp4"))
            {
                BitmapImage image = new BitmapImage(new Uri("/Images/video.png", UriKind.Relative));
                image.CreateOptions = BitmapCreateOptions.BackgroundCreation;
                return image;
            }

            if (MCSManager.Instance.isInternetConnectionAvailable)
                return value;
            else
            {
                BitmapImage image = new BitmapImage(new Uri("/Images/defaultImage.png", UriKind.Relative));
                image.CreateOptions = BitmapCreateOptions.BackgroundCreation;
                return image;
            }


        }
        return new Uri("/Images/defaultImage.png", UriKind.Relative);

    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }

}

Windows 10码

public class ImageConverter:IValueConverter
{
    StorageFolder localFolder = ApplicationData.Current.LocalFolder;
    public object Convert(object value, Type targetType, object parameter, string culture)
    {
        if (value != null)
        {
            string imageUrl = value.ToString();

            if (imageUrl.Contains("NoImageIcon"))
                return value;

            if (imageUrl.Contains(Constants.IMAGES_FOLDER_PATH))
            {
                BitmapImage image = new BitmapImage();
                image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
                System.Threading.Tasks.Task.Factory.StartNew(async()=>
                    {
                        StorageFile imagefile = await localFolder.GetFileAsync(imageUrl);
                        using (IRandomAccessStream fileStream=await imagefile.OpenAsync(FileAccessMode.ReadWrite))
                        {

                            image.SetSource(fileStream);
                            return image;
                        }
                    });
            }

            if (imageUrl.Contains("mp4"))
            {
                BitmapImage image = new BitmapImage(new Uri("ms-appx:///Images/video.png", UriKind.RelativeOrAbsolute));
                image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
                return image;
            }

            if (MCSManager.Instance.isInternetConnectionAvailable)
                return value;
            else
            {
                BitmapImage image = new BitmapImage(new Uri("ms-appx:///Images/defaultImage.png", UriKind.RelativeOrAbsolute));
                image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
                return image;
            }


        }
        return new Uri("ms-appx:///Images/defaultImage.png", UriKind.RelativeOrAbsolute);

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


    private async Task<bool> FileExists(string fileName)
    {
        try
        {
            StorageFile file =await localFolder.GetFileAsync(fileName);
            return true;
        }
        catch(FileNotFoundException ex)
        {
            return false;
        }
    }
}

我想在我的 ListView DataTemplate 中使用这个转换器。我的数据模板是

<DataTemplate x:Key="NEWReportEvidenceListItemTemplate">
    <UserControl>
        <Grid>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup>
                    <VisualState>
                        <VisualState.StateTriggers>
                            <AdaptiveTrigger MinWindowWidth="0"/>
                        </VisualState.StateTriggers>
                        <VisualState.Setters>
                            <Setter Target="DFImage.Width" Value="70"/>
                            <Setter Target="DFImage.Height" Value="70"/>
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState>
                        <VisualState.StateTriggers>
                            <AdaptiveTrigger MinWindowWidth="720"/>
                        </VisualState.StateTriggers>
                        <VisualState.Setters>
                            <Setter Target="DFImage.Width" Value="108"/>
                            <Setter Target="DFImage.Height" Value="108"/>
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <Image DataContext="{Binding EvidencePath,Converter={StaticResource ImageConverter}}"
                   Source="{Binding Result}"
                   x:Name="DFImage"
                   Margin="4,0,0,0"
                   Stretch="Uniform"/>
        </Grid>
    </UserControl>
</DataTemplate>

使用此绑定

<Image DataContext="{Binding ImageUrl, Converter={StaticResource ImageConverter}}" Stretch="Uniform" 
           Source="{Binding Result}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>

转换器class

public class ImageConverter : IValueConverter
{
    StorageFolder localFolder = ApplicationData.Current.LocalFolder;
    public object Convert(object value, Type targetType, object parameter, string culture)
    {
        if (value != null)
        {
            string imageUrl = value.ToString();

            if (imageUrl.Contains("NoImageIcon"))
                return value;

            if (imageUrl.Contains(Constants.IMAGES_FOLDER_PATH))
            {
                var task = Task.Run(()=>( (GetImage((String)value))));
                 return new TaskCompletionNotifier<BitmapImage>(task);

            }

            if (imageUrl.Contains("mp4"))
            {
                return new TaskCompletionNotifier<BitmapImage>(Task.Run(() => ((GetImage("ms-appx:///Images/video.png")))));


            }

            if (MCSManager.Instance.isInternetConnectionAvailable)
            {
                return new TaskCompletionNotifier<BitmapImage>(Task.Run(() => ((GetImage(value.ToString(),true)))));
            }
            else
            {
                var task = Task.Run(() => ((GetImage("ms-appx:///Images/defaultImage.png"))));
                return new TaskCompletionNotifier<BitmapImage>(task);
            }


        }
        return new Uri("ms-appx:///Images/defaultImage.png", UriKind.RelativeOrAbsolute);

    }
    private async Task<BitmapImage> GetImage(string path,bool link=false)
    {
        BitmapImage image=null;
        var dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
        try
        {

          await  dispatcher.RunAsync(CoreDispatcherPriority.Normal,async () =>
            {
                if (link)
                {
                    image = new BitmapImage();
                    image.UriSource = new Uri(path, UriKind.RelativeOrAbsolute);

                }
                else
                {
                    image = new BitmapImage();
                    image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;

                    StorageFile imagefile = await localFolder.GetFileAsync(path);
                    using (IRandomAccessStream fileStream = await imagefile.OpenAsync(FileAccessMode.ReadWrite))
                    {

                        image.SetSource(fileStream);

                    }
                }
            });
            return image;
        }
        catch(Exception e)
        {
            return null;
        }


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


    private async Task<bool> FileExists(string fileName)
    {
        try
        {
            StorageFile file = await localFolder.GetFileAsync(fileName);
            return true;
        }
        catch (FileNotFoundException ex)
        {
            return false;
        }
    }
}
public sealed class TaskCompletionNotifier<TResult> : INotifyPropertyChanged
{
    public TaskCompletionNotifier(Task<TResult> task)
    {
        Task = task;
        if (!task.IsCompleted)
        {
            var scheduler = (SynchronizationContext.Current == null) ? TaskScheduler.Current : TaskScheduler.FromCurrentSynchronizationContext();
            task.ContinueWith(t =>
            {
                var propertyChanged = PropertyChanged;
                if (propertyChanged != null)
                {
                    propertyChanged(this, new PropertyChangedEventArgs("IsCompleted"));
                    if (t.IsCanceled)
                    {
                        propertyChanged(this, new PropertyChangedEventArgs("IsCanceled"));
                    }
                    else if (t.IsFaulted)
                    {
                        propertyChanged(this, new PropertyChangedEventArgs("IsFaulted"));
                        propertyChanged(this, new PropertyChangedEventArgs("ErrorMessage"));
                    }
                    else
                    {
                        propertyChanged(this, new PropertyChangedEventArgs("IsSuccessfullyCompleted"));
                        propertyChanged(this, new PropertyChangedEventArgs("Result"));
                    }
                }
            },
            CancellationToken.None,
            TaskContinuationOptions.ExecuteSynchronously,
            scheduler);
        }
    }

    // Gets the task being watched. This property never changes and is never <c>null</c>.
    public Task<TResult> Task { get; private set; }



    // Gets the result of the task. Returns the default value of TResult if the task has not completed successfully.
    public TResult Result { get { return (Task.Status == TaskStatus.RanToCompletion) ? Task.Result : default(TResult); } }

    // Gets whether the task has completed.
    public bool IsCompleted { get { return Task.IsCompleted; } }

    // Gets whether the task has completed successfully.
    public bool IsSuccessfullyCompleted { get { return Task.Status == TaskStatus.RanToCompletion; } }

    // Gets whether the task has been canceled.
    public bool IsCanceled { get { return Task.IsCanceled; } }

    // Gets whether the task has faulted.
    public bool IsFaulted { get { return Task.IsFaulted; } }


    public event PropertyChangedEventHandler PropertyChanged;
}

我正在从转换器返回任务并将其设置为图像的 DataContext。任务有 Result 属性,我将其绑定到 Source 属性

Referred from this link