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

如何基于Xamarin与SQL Server实现ListView按钮触发PDF数据库下载

在Xamarin.Forms ListView中实现点击按钮下载对应ID的PDF文件

我来帮你搞定这个需求!要实现点击ListView项里的按钮,根据对应ID从SQL Server下载PDF文件,咱们分步骤来实现:

1. 先修改你的XAML,添加下载按钮

首先在你的ListView项模板里加入下载按钮,注意要把命令绑定到页面的ViewModel(而不是单个数据项),同时把当前项的ID作为命令参数传递:

<!-- 记得给你的ListView设置x:Name="YourListView" -->
<ListView x:Name="YourListView" ...>
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <StackLayout Orientation="Vertical" Padding="12,6">
                    <Label Text="{Binding Name}" FontSize="24" Style="{DynamicResource ListItemTextStyle}" />
                    <!-- 添加下载按钮 -->
                    <Button Text="下载PDF" 
                            Command="{Binding BindingContext.DownloadPdfCommand, Source={x:Reference Name=YourListView}}"
                            CommandParameter="{Binding Id}"
                            Margin="0,8,0,0"/>
                </StackLayout>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

注意:把YourListView替换成你自己ListView的实际x:Name值,Id是你数据模型里对应数据库ID的属性名。

2. 在页面ViewModel中实现下载命令

假设你的页面ViewModel已经实现了INotifyPropertyChanged,添加一个用于处理下载的命令,并编写核心的下载逻辑:

using System.Windows.Input;
using Xamarin.Forms;

public class YourPageViewModel : INotifyPropertyChanged
{
    // 数据库服务实例,你可以根据实际情况注入或初始化
    private readonly YourDatabaseService _dbService = new YourDatabaseService();

    public ICommand DownloadPdfCommand { get; }

    public YourPageViewModel()
    {
        // 初始化命令,接收int类型的ID参数
        DownloadPdfCommand = new Command<int>(async (pdfId) => await HandlePdfDownloadAsync(pdfId));
    }

    private async Task HandlePdfDownloadAsync(int pdfId)
    {
        try
        {
            // 从SQL Server获取PDF的字节数组
            var pdfBytes = await _dbService.GetPdfBytesByIdAsync(pdfId);
            
            if (pdfBytes == null || pdfBytes.Length == 0)
            {
                await Application.Current.MainPage.DisplayAlert("提示", "未找到对应的PDF文件", "确定");
                return;
            }

            // 调用跨平台文件保存服务
            var saveSuccess = await DependencyService.Get<IFileSaver>().SavePdfAsync(pdfBytes, $"文档_{pdfId}.pdf");
            
            if (saveSuccess)
            {
                await Application.Current.MainPage.DisplayAlert("成功", "PDF文件已保存到设备", "确定");
            }
            else
            {
                await Application.Current.MainPage.DisplayAlert("失败", "保存PDF时出现错误", "确定");
            }
        }
        catch (Exception ex)
        {
            await Application.Current.MainPage.DisplayAlert("错误", $"下载失败:{ex.Message}", "确定");
        }
    }

    // 这里实现INotifyPropertyChanged的代码(省略,你应该已经有了)
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

3. 实现从SQL Server获取PDF的数据库服务

编写一个数据库服务类,负责根据ID从SQL Server读取PDF文件的字节数组(假设你的PDF存在varbinary(max)类型的字段里):

using System.Data.SqlClient;
using Dapper; // 如果你用Dapper,也可以用EF Core替代

public class YourDatabaseService
{
    // 替换成你的SQL Server连接字符串
    private readonly string _connectionString = "Server=YOUR_SERVER;Database=YOUR_DB;User Id=YOUR_USER;Password=YOUR_PWD;";

    public async Task<byte[]> GetPdfBytesByIdAsync(int pdfId)
    {
        using (var conn = new SqlConnection(_connectionString))
        {
            await conn.OpenAsync();
            // 替换成你的实际表名和字段名
            var query = "SELECT PdfContent FROM PdfFiles WHERE Id = @Id";
            return await conn.QueryFirstOrDefaultAsync<byte[]>(query, new { Id = pdfId });
        }
    }
}

提示:如果用EF Core,直接查询实体的对应字节数组字段即可,逻辑类似。

4. 实现跨平台文件保存的依赖服务

因为Xamarin.Forms无法直接操作各平台的文件系统,我们用DependencyService来实现平台特定的保存逻辑:

第一步:在共享项目定义接口

public interface IFileSaver
{
    Task<bool> SavePdfAsync(byte[] pdfBytes, string fileName);
}

第二步:Android平台实现

在Android项目中添加以下类,记得添加必要的权限:

[assembly: Dependency(typeof(FileSaver_Android))]
namespace YourAppNamespace.Droid
{
    public class FileSaver_Android : IFileSaver
    {
        public async Task<bool> SavePdfAsync(byte[] pdfBytes, string fileName)
        {
            try
            {
                // 保存到设备的下载目录
                var downloadPath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
                var filePath = Path.Combine(downloadPath, fileName);

                using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    await stream.WriteAsync(pdfBytes, 0, pdfBytes.Length);
                }

                // 通知系统刷新媒体库,让用户能在文件管理器中看到
                var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
                mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(filePath)));
                Android.App.Application.Context.SendBroadcast(mediaScanIntent);

                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

别忘了在AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Android 10及以上需要这个权限 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

第三步:iOS平台实现

在iOS项目中添加以下类:

[assembly: Dependency(typeof(FileSaver_iOS))]
namespace YourAppNamespace.iOS
{
    public class FileSaver_iOS : IFileSaver
    {
        public async Task<bool> SavePdfAsync(byte[] pdfBytes, string fileName)
        {
            try
            {
                // 保存到应用的文档目录
                var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                var filePath = Path.Combine(documentsPath, fileName);

                await File.WriteAllBytesAsync(filePath, pdfBytes);

                // 弹出分享/打开菜单,让用户选择操作
                var fileUrl = NSUrl.FromFilename(filePath);
                var rootViewController = UIApplication.SharedApplication.KeyWindow.RootViewController;
                var activityVC = new UIActivityViewController(new[] { fileUrl }, null);
                
                rootViewController.PresentViewController(activityVC, true, null);

                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

这样一套流程下来,用户点击ListView项里的下载按钮,就能根据对应ID从SQL Server获取PDF并保存到设备上了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:10:07