# Upload 使用文档 本文档介绍 AtomUI Upload 控件的各种使用方式,示例代码摘自 Gallery 演示程序。 > 📖 Gallery 源码位置:`controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/UploadShowCase.axaml` --- ## 前置准备 在 AXAML 中使用 Upload,需要引入以下命名空间: ```xml xmlns:atom="https://atomui.net" xmlns:antdicons="https://atomui.net/icons/antdesign" ``` 在 C# 代码中引入: ```csharp using AtomUI.Desktop.Controls; // Upload, UploadDefaultDropArea, UploadTaskInfo 等 using AtomUI.Controls; // IFileUploadTransport, FileUploadResult, UploadFileInfo 等 ``` --- ## 1. 基本点击上传 最基础的上传用法——点击按钮弹出文件选择对话框: ```xml Click to Upload ``` ```csharp // Code-behind:设置上传传输实现 BasicUpload.UploadTransport = new MyUploadTransport(); // 监听事件 BasicUpload.UploadTaskCompleted += (sender, e) => { // 上传成功处理 Console.WriteLine($"{e.UploadFileInfo.Name} uploaded successfully!"); }; BasicUpload.UploadTaskFailed += (sender, e) => { // 上传失败处理 Console.WriteLine($"Upload failed: {e.Result.UserFriendlyMessage}"); }; ``` **要点**:Upload 控件的 `Content` 可以是任何控件,点击触发区域时会自动弹出文件选择对话框。必须设置 `UploadTransport` 属性才能实际上传文件。 --- ## 2. 头像上传(PictureCard / PictureCircle) 使用 `PictureCard` 或 `PictureCircle` 列表类型实现头像上传效果: ```xml Upload Upload ``` **要点**: - `PictureCard` 和 `PictureCircle` 类型的触发按钮会嵌入到图片网格中,显示为一个带「+」的卡片。 - 可通过 `IsTaskRunning` 属性绑定动态切换加载图标。 --- ## 3. 默认文件列表 使用 `DefaultTaskList` 属性在页面初始化时展示已有文件: ```xml Click to Upload ``` ```csharp // Code-behind 或 ViewModel 中设置默认列表 var defaultTasks = new List { new UploadTaskInfo { TaskId = Guid.NewGuid(), FileName = "xxx.png", IsImageFile = true, Status = FileUploadStatus.Uploading, Progress = 33 }, new UploadTaskInfo { TaskId = Guid.NewGuid(), FileName = "yyy.png", IsImageFile = true, Status = FileUploadStatus.Success, Progress = 100 }, new UploadTaskInfo { TaskId = Guid.NewGuid(), FileName = "zzz.png", IsImageFile = true, Status = FileUploadStatus.Failed, ErrorMessage = "Server Error 500" } }; DefaultFileList.DefaultTaskList = defaultTasks; ``` **要点**:`DefaultTaskList` 在控件首次加载时应用一次,支持展示不同状态(上传中、成功、失败)的文件。 --- ## 4. 图片墙(Pictures Wall) 使用 `PictureCard` 列表类型实现图片墙效果,配合默认文件列表展示已有图片: ```xml Upload ``` ```csharp // 设置已有图片列表 PicturesWallUpload.DefaultTaskList = new List { new UploadTaskInfo { TaskId = Guid.NewGuid(), FileName = "image.png", IsImageFile = true, Status = FileUploadStatus.Success, FilePath = new Uri("avares://AtomUIGallery/Assets/ImagePreviewerShowCase/1.png") }, // ... 更多图片 }; PicturesWallUpload.UploadTransport = new MyUploadTransport(); ``` **要点**: - `FilePath` 可以使用 `avares://` 协议引用应用程序内嵌资源。 - 成功上传的图片会自动显示缩略图预览。 - 悬浮已上传图片时会显示遮罩层和操作按钮(预览/删除)。 --- ## 5. 拖拽上传 使用 `UploadDefaultDropArea` 作为触发区内容,支持拖拽文件上传: ```xml ``` ```csharp DragAndDropUpload.UploadTransport = new MyUploadTransport(); ``` **自定义拖拽区域内容**: ```xml ``` **要点**: - `UploadDefaultDropArea` 开箱即用,已内置 `DragDrop.AllowDrop` 和虚线边框样式。 - 悬浮时边框高亮为主色调。 - `Header` 默认为本地化文本「Click or drag file to this area to upload」。 --- ## 6. 图片列表(Picture List) 使用 `Picture` 列表类型,在文本列表基础上增加缩略图预览: ```xml Click to Upload ``` --- ## 7. 最大文件数限制 通过 `MaxCount` 属性限制上传文件数量: ```xml Upload (Max: 1) Upload (Max: 3) ``` **行为说明**: - `MaxCount=1` 时,选择新文件会自动取消并替换现有文件。 - `MaxCount>1` 时,达到上限后选择的新文件会被静默忽略。 --- ## 8. 目录上传 启用 `IsUploadDirectoryEnabled` 属性可选择整个目录上传: ```xml Upload Directory ``` **要点**:选择目录后,会遍历目录中的所有文件(仅顶层)逐一创建上传任务。 --- ## 9. 文件类型过滤 ### 使用 Accepts 属性过滤(对话框级别) ```xml Upload png only ``` ### 使用 UploadTaskAboutToScheduling 事件拦截(逻辑级别) ```csharp // 仅允许 JPG/PNG 且小于 2MB 的图片 AvatarUpload.UploadTaskAboutToScheduling += (sender, e) => { var fileInfo = e.UploadFileInfo; var ext = Path.GetExtension(fileInfo.FilePath.LocalPath); // 文件类型校验 if (ext != ".jpeg" && ext != ".jpg" && ext != ".png") { e.Result = UploadPredicateResult.CancelWithInTaskList; e.CancelReason = "You can only upload JPG/PNG file!"; return; } // 文件大小校验 var isLt2M = (double)fileInfo.Size / 1024 / 1024 < 2; if (!isLt2M) { e.Result = UploadPredicateResult.CancelWithInTaskList; e.CancelReason = "Image must smaller than 2MB!"; } }; ``` ```csharp // 仅允许 PNG 文件,不符合条件的文件从列表中隐藏 PngOnlyUpload.UploadTaskAboutToScheduling += (sender, e) => { var ext = Path.GetExtension(e.UploadFileInfo.FilePath.LocalPath); if (ext != ".png") { e.Result = UploadPredicateResult.Cancel; // 不显示在列表中 e.CancelReason = "You can only upload PNG file!"; } }; ``` **`UploadPredicateResult` 行为对比**: - `Cancel`:文件不显示在列表中(对标 Ant Design 的 `Upload.LIST_IGNORE`) - `CancelWithInTaskList`:文件显示在列表中但标记为失败 --- ## 10. 实现自定义上传传输 实现 `IFileUploadTransport` 接口提供实际的上传逻辑: ```csharp public class HttpUploadTransport : IFileUploadTransport { private readonly HttpClient _httpClient; private readonly string _uploadUrl; public HttpUploadTransport(string uploadUrl) { _httpClient = new HttpClient(); _uploadUrl = uploadUrl; } public async Task UploadAsync( UploadFileInfo fileInfo, object? context = null, IProgress? progress = null, CancellationToken cancellationToken = default) { try { var startTime = DateTime.Now; using var stream = File.OpenRead(fileInfo.FilePath.LocalPath); using var content = new StreamContent(stream); using var form = new MultipartFormDataContent(); form.Add(content, "file", fileInfo.Name); var response = await _httpClient.PostAsync(_uploadUrl, form, cancellationToken); response.EnsureSuccessStatusCode(); var elapsed = DateTime.Now - startTime; return FileUploadResult.SuccessResult( new Uri($"{_uploadUrl}/{fileInfo.Name}"), fileInfo.Size, elapsed); } catch (OperationCanceledException) { throw; } catch (Exception ex) { return FileUploadResult.FailureResult( FileUploadErrorCode.NetworkError, $"Upload failed: {ex.Message}", exception: ex); } } } ``` ```csharp // 使用自定义传输 myUpload.UploadTransport = new HttpUploadTransport("https://api.example.com/upload"); ``` --- ## 11. 上传事件处理与消息反馈 结合消息提示组件提供上传反馈: ```csharp // 上传失败时显示错误消息 upload.UploadTaskFailed += (sender, e) => { messageManager?.Show(new Message( type: MessageType.Error, content: e.Result.UserFriendlyMessage ?? "Upload failed" )); }; // 上传成功时显示成功消息 upload.UploadTaskCompleted += (sender, e) => { messageManager?.Show(new Message( type: MessageType.Success, content: $"{e.UploadFileInfo.Name} upload successfully!" )); }; ``` > 📖 参考:`controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/UploadShowCase.axaml.cs` --- ## 12. 控制显示/隐藏 ```xml Upload ``` --- ## 13. 重置上传控件 ```csharp // 异步重置(取消所有任务并清空列表) await myUpload.ResetAsync(); // 同步版本(内部调度到 UI 线程) myUpload.Reset(); ``` --- ## 常见组合模式 ### 带反馈的完整上传流程 ```xml Click to Upload ``` ```csharp // 初始化 MyUpload.UploadTransport = new HttpUploadTransport("https://api.example.com/upload"); MyUpload.MaxConcurrentTasks = 2; // 上传前校验 MyUpload.UploadTaskAboutToScheduling += (s, e) => { if (e.UploadFileInfo.Size > 10 * 1024 * 1024) { e.Result = UploadPredicateResult.CancelWithInTaskList; e.CancelReason = "File must be smaller than 10MB"; } }; // 事件监听 MyUpload.UploadTaskCompleted += HandleCompleted; MyUpload.UploadTaskFailed += HandleFailed; // 清理 Disposable.Create(() => { MyUpload.UploadTransport = null; MyUpload.UploadTaskCompleted -= HandleCompleted; MyUpload.UploadTaskFailed -= HandleFailed; MyUpload.Reset(); }); ``` ### 使用 ReactiveUI 绑定 ```csharp this.WhenActivated(disposables => { this.OneWayBind(ViewModel, m => m.DefaultFiles, v => v.MyUpload.DefaultTaskList) .DisposeWith(disposables); }); ```