假设我有一个
Image
,其 Source
来自绑定表达式,绑定到 URL(作为 string
):
<Image Source="{Binding WebformatUrl}" />
WPF 下载图像并显示它。
有什么方法可以将 WPF 下载的图像保存到磁盘上吗?
一种方法是使用
IValueConverter
进行绑定:
<Window x:Class="wpf_image_source_to_disk.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:wpf_image_source_to_disk"
mc:Ignorable="d"
Title="MainWindow" Width="500" Height="300" >
<Window.DataContext>
<local:MainPageBindingContext/>
</Window.DataContext>
<Window.Resources>
<local:StringToImageAsyncConverter x:Key="StringToImageAsyncConverter" />
</Window.Resources>
<Grid>
<Image Source="{
Binding WebFormatUrl,
Converter={StaticResource StringToImageConverter}
}" Margin="20"/>
</Grid>
</Window>
下载并返回图像后,保存方法被称为异步,并且(在本示例中)在默认编辑器(例如 MSPaint)中打开保存的文件。
class StringToImageConverter : IValueConverter
{
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string url && !string.IsNullOrEmpty(url))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri(url);
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit(); bitmapImage.DownloadCompleted += (s, e) =>
{
_ = SaveFileAsync(url, bitmapImage);
};
return bitmapImage;
}
else return new BitmapImage();
}
private async Task SaveFileAsync(string url, BitmapImage imageToSave)
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(imageToSave));
var tmpFileNameForTest = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
Assembly.GetExecutingAssembly().GetName().Name,
"Images",
"tmp.jpg");
Directory.CreateDirectory(Path.GetDirectoryName(tmpFileNameForTest));
if(File.Exists(tmpFileNameForTest) )
{
File.Delete(tmpFileNameForTest);
}
using (FileStream fileStream = new FileStream(tmpFileNameForTest, FileMode.Create))
{
encoder.Save(fileStream);
}
await Task.Delay(TimeSpan.FromSeconds(1));
{
try
{
Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = tmpFileNameForTest, });
}
catch
{
Debug.Fail("Couldn't start default editor");
}
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotImplementedException();
}