如何在 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
我正在将我的 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