You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UWP C#:如何在应用设置中保存并加载图像/文件流?

解决方案:保存与加载UWP ListView中的BitmapImage

针对你的需求,直接保存BitmapImage是不可行的——它是UI绑定对象,不支持序列化。这里提供两种实用方案,你可以根据场景选择:

方案一:将图像转为字节数组保存(不依赖原始文件)

这种方式把图像编码为字节数组(再转成Base64字符串)存储到应用设置,加载时反向解析。优点是不依赖原始文件,即使用户删除了原图片也能正常显示;缺点是大图像会占用较多设置空间,且序列化/反序列化有轻微性能开销。

步骤1:实现BitmapImage转字节数组的方法

private async Task<byte[]> BitmapImageToByteArray(BitmapImage bitmapImage)
{
    byte[] bytes = null;
    using (var stream = new InMemoryRandomAccessStream())
    {
        // 使用PNG编码避免质量损失
        var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
        var writeableBitmap = new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
        await writeableBitmap.SetSourceAsync(await bitmapImage.OpenReadAsync());
        
        encoder.SetPixelData(
            BitmapPixelFormat.Bgra8,
            BitmapAlphaMode.Premultiplied,
            (uint)writeableBitmap.PixelWidth,
            (uint)writeableBitmap.PixelHeight,
            DisplayInformation.GetForCurrentView().LogicalDpi,
            DisplayInformation.GetForCurrentView().LogicalDpi,
            writeableBitmap.PixelBuffer.ToArray()
        );
        
        await encoder.FlushAsync();
        bytes = new byte[stream.Size];
        await stream.AsStream().ReadAsync(bytes, 0, bytes.Length);
    }
    return bytes;
}

步骤2:保存图像到应用设置

建议用模型类封装每项数据,避免文本和图像的对应关系混乱:

// 定义模型类封装每项数据
public class ListItemModel
{
    public string TextBoxContent { get; set; }
    public string ImageBase64 { get; set; } // 存储图像的Base64字符串
}

// 保存所有项的方法
private async Task SaveAllItems()
{
    var savedItems = new List<ListItemModel>();
    foreach (var item in yourListView.Items) // 遍历ListView的所有项
    {
        var model = item as ListItemModel;
        if (model == null) continue;
        
        // 匹配当前项对应的图像
        var targetImg = imglist.ElementAt(savedItems.Count);
        if (targetImg != null && targetImg.UriSource != null)
        {
            var imgBytes = await BitmapImageToByteArray(targetImg);
            model.ImageBase64 = Convert.ToBase64String(imgBytes);
        }
        else
        {
            model.ImageBase64 = string.Empty;
        }
        
        savedItems.Add(model);
    }
    
    // 序列化模型列表到设置(使用System.Text.Json)
    var json = JsonSerializer.Serialize(savedItems);
    ApplicationData.Current.LocalSettings.Values["SavedListViewItems"] = json;
}

步骤3:从设置加载图像

private async Task LoadAllItems()
{
    imglist.Clear();
    yourListView.Items.Clear();
    
    if (!ApplicationData.Current.LocalSettings.Values.ContainsKey("SavedListViewItems"))
        return;
    
    var json = ApplicationData.Current.LocalSettings.Values["SavedListViewItems"] as string;
    var savedItems = JsonSerializer.Deserialize<List<ListItemModel>>(json);
    
    foreach (var model in savedItems)
    {
        // 加载文本(复用你已实现的逻辑)
        
        // 加载图像
        if (!string.IsNullOrEmpty(model.ImageBase64))
        {
            var imgBytes = Convert.FromBase64String(model.ImageBase64);
            using (var stream = new InMemoryRandomAccessStream())
            {
                await stream.WriteAsync(imgBytes.AsBuffer());
                stream.Seek(0);
                var bitmap = new BitmapImage();
                await bitmap.SetSourceAsync(stream);
                imglist.Add(bitmap);
            }
        }
        else
        {
            imglist.Add(new BitmapImage());
        }
        
        yourListView.Items.Add(model);
    }
}

方案二:保存文件访问权限(依赖原始文件)

利用UWP的FutureAccessList保存用户选择文件的访问权限,只存储权限Token到设置。优点是节省空间,图像质量无损失;缺点是依赖原始文件存在,且FutureAccessList最多存储1000个项。

步骤1:选择文件时保存访问Token

修改你的文件选择逻辑,把文件添加到FutureAccessList并记录Token:

// 定义模型类封装每项数据
public class ListItemModel
{
    public string TextBoxContent { get; set; }
    public string ImageFileToken { get; set; } // 存储文件访问Token
}

private async void openFileInputEvent(object sender, RoutedEventArgs e)
{
    var picker = new Windows.Storage.Pickers.FileOpenPicker();
    picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail;
    picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
    picker.FileTypeFilter.Add(".jpg");
    picker.FileTypeFilter.Add(".jpeg");
    picker.FileTypeFilter.Add(".png");
    
    Windows.Storage.StorageFile file = await picker.PickSingleFileAsync();
    if (file != null)
    {
        // 添加到FutureAccessList,获取长期访问Token
        string token = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(file);
        
        using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
        {
            BitmapImage tmpimg = new BitmapImage();
            await tmpimg.SetSourceAsync(fileStream);
            imglist.Add(tmpimg);
        }
        
        // 创建模型并添加到ListView(绑定文本和Token)
        yourListView.Items.Add(new ListItemModel { TextBoxContent = "...", ImageFileToken = token });
    }
    else
    {
        var dialog = new MessageDialog("File not chosen", "No chosen Image");
        await dialog.ShowAsync();
        imglist.Add(new BitmapImage());
        yourListView.Items.Add(new ListItemModel { TextBoxContent = "...", ImageFileToken = string.Empty });
    }
}

步骤2:保存Token和文本到设置

private void SaveAllItems()
{
    var savedItems = yourListView.Items.Cast<ListItemModel>().ToList();
    var json = JsonSerializer.Serialize(savedItems);
    ApplicationData.Current.LocalSettings.Values["SavedListViewItems"] = json;
}

步骤3:从设置加载图像

private async Task LoadAllItems()
{
    imglist.Clear();
    yourListView.Items.Clear();
    
    if (!ApplicationData.Current.LocalSettings.Values.ContainsKey("SavedListViewItems"))
        return;
    
    var json = ApplicationData.Current.LocalSettings.Values["SavedListViewItems"] as string;
    var savedItems = JsonSerializer.Deserialize<List<ListItemModel>>(json);
    
    foreach (var model in savedItems)
    {
        // 加载文本(复用你已实现的逻辑)
        
        // 加载图像
        if (!string.IsNullOrEmpty(model.ImageFileToken))
        {
            try
            {
                // 通过Token获取文件
                StorageFile file = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFileAsync(model.ImageFileToken);
                using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
                {
                    BitmapImage tmpimg = new BitmapImage();
                    await tmpimg.SetSourceAsync(fileStream);
                    imglist.Add(tmpimg);
                }
            }
            catch (Exception ex)
            {
                // 处理文件无法访问的情况(如文件被删除、权限失效)
                imglist.Add(new BitmapImage());
            }
        }
        else
        {
            imglist.Add(new BitmapImage());
        }
        
        yourListView.Items.Add(model);
    }
}

方案选择建议

  • 如果希望图像不依赖原始文件,优先选方案一;
  • 如果图像较大,且信任用户不会删除原始文件,优先选方案二。

内容的提问来源于stack exchange,提问作者Techrex Studios

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:57:45