Skip to content

不打开文件对话框上传文件

概述

在FBro浏览器自动化过程中,有时需要模拟文件上传操作但不希望弹出系统文件对话框。FBro提供了通过OnFileDialog事件拦截文件对话框并自动选择文件的机制,实现静默文件上传功能。

核心概念

文件对话框拦截机制

  • 事件拦截:通过OnFileDialog事件拦截浏览器打开文件对话框的操作
  • 自动选择:预先设置文件路径,自动完成文件选择
  • 静默上传:用户不会看到文件对话框,实现自动化上传
  • 多文件支持:支持单个和多个文件的自动选择

关键组件

  • FBroSharpFileDialogCallbackDis:文件对话框回调处理器
  • FBroSharpFileDialogModeType:文件对话框类型枚举
  • IFBroSharpFileDialogEventCallback:文件对话框事件回调接口

基础实现

1. 触发文件对话框

csharp
/// <summary>
/// 触发文件选择对话框
/// </summary>
/// <param name="browser">浏览器实例</param>
/// <param name="title">对话框标题</param>
/// <param name="defaultPath">默认路径</param>
public void TriggerFileDialog(IFBroSharpBrowser browser, string title = "选择文件", string defaultPath = null)
{
    try
    {
        // 设置为拖拽状态,表示需要自动选择文件
        is_dragging = true;
        
        // 创建文件对话框回调处理器
        var callback = new FBroSharpFileDialogCallbackDis();
        
        // 使用当前目录作为默认路径
        string currentPath = defaultPath ?? Directory.GetCurrentDirectory();
        
        // 运行文件对话框
        browser.RunFileDialog(
            FBroSharpFileDialogModeType.FILE_DIALOG_OPEN, 
            title, 
            currentPath, 
            default, 
            callback
        );
        
        Console.WriteLine($"文件对话框已触发: {title}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"触发文件对话框失败: {ex.Message}");
        is_dragging = false;
    }
}

2. 预设文件选择逻辑

csharp
private bool is_dragging = false;
private List<string> predefinedFiles = new List<string>();

/// <summary>
/// 设置预定义的文件列表
/// </summary>
/// <param name="filePaths">文件路径列表</param>
public void SetPredefinedFiles(List<string> filePaths)
{
    predefinedFiles.Clear();
    
    // 验证文件是否存在
    foreach (string filePath in filePaths)
    {
        if (File.Exists(filePath))
        {
            predefinedFiles.Add(filePath);
            Console.WriteLine($"添加预定义文件: {filePath}");
        }
        else
        {
            Console.WriteLine($"警告:文件不存在: {filePath}");
        }
    }
}

/// <summary>
/// 选择文件的核心逻辑
/// </summary>
/// <returns>要上传的文件路径列表</returns>
public List<string> SelectFiles()
{
    if (is_dragging && predefinedFiles.Count > 0)
    {
        Console.WriteLine($"自动选择 {predefinedFiles.Count} 个预定义文件");
        return new List<string>(predefinedFiles);
    }
    else
    {
        Console.WriteLine("没有可选择的文件或未处于自动选择状态");
        return new List<string>();
    }
}

事件处理实现

BrowserEvent.cs 文件对话框事件处理

csharp
/// <summary>
/// 浏览器即将打开文件对话框事件处理
/// </summary>
/// <param name="browser">浏览器实例</param>
/// <param name="mode">对话框模式</param>
/// <param name="title">对话框标题</param>
/// <param name="default_file_path">默认文件路径</param>
/// <param name="accept_filters">接受的文件过滤器</param>
/// <param name="callback">事件回调</param>
/// <returns>是否处理了对话框</returns>
public override bool OnFileDialog(IFBroSharpBrowser browser, 
    FBroSharpFileDialogModeType mode, 
    string title, 
    string default_file_path, 
    out List<string> accept_filters, 
    IFBroSharpFileDialogEventCallback callback)
{
    accept_filters = new List<string>();
    
    try
    {
        // 设置文件过滤器
        SetFileFilters(accept_filters, mode);
        
        // 获取要选择的文件
        List<string> selectedFiles = _form.SelectFiles();
        
        Console.WriteLine($"文件对话框模式: {mode}");
        Console.WriteLine($"对话框标题: {title}");
        Console.WriteLine($"默认路径: {default_file_path}");
        Console.WriteLine($"选择的文件数量: {selectedFiles.Count}");
        
        if (selectedFiles.Count > 0)
        {
            // 验证文件是否存在
            var validFiles = ValidateFiles(selectedFiles);
            
            if (validFiles.Count > 0)
            {
                // 继续文件选择流程
                callback.Continue(validFiles);
                
                Console.WriteLine("文件对话框处理成功,文件已自动选择");
                return true; // 表示已处理,不显示系统对话框
            }
            else
            {
                Console.WriteLine("没有有效的文件可选择");
            }
        }
        
        // 如果没有文件或文件无效,取消对话框
        callback.Dispose();
        Console.WriteLine("文件对话框已取消");
        return false; // 表示未处理,可能显示系统对话框
    }
    catch (Exception ex)
    {
        Console.WriteLine($"处理文件对话框时出错: {ex.Message}");
        
        try
        {
            callback.Dispose();
        }
        catch { }
        
        return false;
    }
}

/// <summary>
/// 设置文件过滤器
/// </summary>
/// <param name="accept_filters">过滤器列表</param>
/// <param name="mode">对话框模式</param>
private void SetFileFilters(List<string> accept_filters, FBroSharpFileDialogModeType mode)
{
    // 根据对话框模式设置不同的过滤器
    switch (mode)
    {
        case FBroSharpFileDialogModeType.FILE_DIALOG_OPEN:
            accept_filters.Add("所有文件 (*.*)|*.*");
            accept_filters.Add("图片文件 (*.jpg;*.png;*.gif)|*.jpg;*.png;*.gif");
            accept_filters.Add("文本文件 (*.txt)|*.txt");
            accept_filters.Add("Word文档 (*.doc;*.docx)|*.doc;*.docx");
            accept_filters.Add("PDF文件 (*.pdf)|*.pdf");
            break;
            
        case FBroSharpFileDialogModeType.FILE_DIALOG_OPEN_MULTIPLE:
            accept_filters.Add("所有文件 (*.*)|*.*");
            accept_filters.Add("图片文件 (*.jpg;*.png;*.gif)|*.jpg;*.png;*.gif");
            break;
            
        default:
            accept_filters.Add("所有文件 (*.*)|*.*");
            break;
    }
}

/// <summary>
/// 验证文件列表
/// </summary>
/// <param name="filePaths">文件路径列表</param>
/// <returns>有效的文件路径列表</returns>
private List<string> ValidateFiles(List<string> filePaths)
{
    var validFiles = new List<string>();
    
    foreach (string filePath in filePaths)
    {
        if (File.Exists(filePath))
        {
            validFiles.Add(filePath);
            Console.WriteLine($"有效文件: {filePath}");
        }
        else
        {
            Console.WriteLine($"无效文件: {filePath}");
        }
    }
    
    return validFiles;
}

对话框模式类型

模式类型说明适用场景
FILE_DIALOG_OPEN单文件选择上传单个文件
FILE_DIALOG_OPEN_MULTIPLE多文件选择批量文件上传
FILE_DIALOG_OPEN_FOLDER文件夹选择选择整个文件夹
FILE_DIALOG_SAVE保存文件文件下载/保存

完整应用示例

1. 图片上传示例

csharp
public class ImageUploadExample
{
    private bool is_dragging = false;
    private List<string> imageFiles = new List<string>();

    /// <summary>
    /// 设置要上传的图片文件
    /// </summary>
    /// <param name="imagePaths">图片文件路径列表</param>
    public void SetImageFiles(List<string> imagePaths)
    {
        imageFiles.Clear();
        
        foreach (string imagePath in imagePaths)
        {
            if (IsValidImageFile(imagePath))
            {
                imageFiles.Add(imagePath);
                Console.WriteLine($"添加图片文件: {Path.GetFileName(imagePath)}");
            }
        }
    }

    /// <summary>
    /// 触发图片上传
    /// </summary>
    /// <param name="browser">浏览器实例</param>
    /// <param name="uploadButtonSelector">上传按钮的CSS选择器</param>
    public async Task<bool> UploadImages(IFBroSharpBrowser browser, string uploadButtonSelector)
    {
        try
        {
            // 1. 设置自动选择状态
            is_dragging = true;
            
            // 2. 查找并点击上传按钮
            bool buttonFound = await ClickUploadButton(browser, uploadButtonSelector);
            if (!buttonFound)
            {
                Console.WriteLine("未找到上传按钮");
                return false;
            }
            
            // 3. 等待文件对话框处理完成
            await Task.Delay(2000);
            
            // 4. 等待上传完成
            bool uploadSuccess = await WaitForUploadComplete(browser);
            
            Console.WriteLine($"图片上传{(uploadSuccess ? "成功" : "失败")}");
            return uploadSuccess;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"图片上传出错: {ex.Message}");
            return false;
        }
        finally
        {
            is_dragging = false;
        }
    }

    /// <summary>
    /// 点击上传按钮(支持两种点击方式)
    /// </summary>
    /// <param name="browser">浏览器实例</param>
    /// <param name="selector">上传按钮的CSS选择器</param>
    /// <returns>是否点击成功</returns>
    private async Task<bool> ClickUploadButton(IFBroSharpBrowser browser, string selector)
    {
        try
        {
            Console.WriteLine($"尝试点击上传按钮: {selector}");
            
            // 方法1: 优先使用发送鼠标点击事件(自动获取坐标)
            bool success = await ClickByMouseEvent(browser, selector);
            
            if (!success)
            {
                Console.WriteLine("发送鼠标点击事件失败,尝试VIP鼠标事件");
                // 方法2: 备用VIP鼠标事件(需要JavaScript获取坐标)
                success = await ClickByVIPControl(browser, selector);
            }
            
            if (success)
            {
                Console.WriteLine("上传按钮点击成功");
                // 等待文件对话框响应
                await Task.Delay(1000);
            }
            else
            {
                Console.WriteLine("所有点击方式都失败了");
            }
            
            return success;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"点击上传按钮异常: {ex.Message}");
            return false;
        }
    }

    /// <summary>
    /// 方法1: 通过发送鼠标点击事件点击按钮
    /// </summary>
    /// <param name="browser">浏览器实例</param>
    /// <param name="selector">元素选择器</param>
    /// <returns>是否成功</returns>
    private async Task<bool> ClickByMouseEvent(IFBroSharpBrowser browser, string selector)
    {
        return await Task.Run(() =>
        {
            try
            {
                var callback = new FBroSharpJsCallbackSyn();
                
                // 获取元素坐标
                browser.GetMainTianBiaoFrame().GetPoint(selector, 0, callback);
                
                if (callback.help != null && callback.help.IsValid)
                {
                    // 等待获取坐标结果
                    callback.help.WaitEvent(10 * 1000);
                    
                    if (callback.help.HavStringData())
                    {
                        string pointData = callback.help.GetStringData();
                        Console.WriteLine($"获取到坐标: {pointData}");
                        
                        // 解析坐标
                        string[] parts = pointData.Split(',');
                        if (parts.Length >= 2)
                        {
                            int x = (int)float.Parse(parts[0]);
                            int y = (int)float.Parse(parts[1]);
                            
                            Console.WriteLine($"发送鼠标点击事件到坐标: ({x}, {y})");
                            
                            // 创建鼠标事件
                            var mouseEvent = new FBroSharpMouseEvent
                            {
                                x = x,
                                y = y,
                                modifiers = FBroSharpEventFlags.EVENTFLAG_LEFT_MOUSE_BUTTON
                            };
                            
                            // 发送鼠标按下和释放事件
                            browser.SendMouseClickEvent(FBroSharpMouseButtonType.MBT_LEFT, mouseEvent, false, 1);
                            Thread.Sleep(50);
                            browser.SendMouseClickEvent(FBroSharpMouseButtonType.MBT_LEFT, mouseEvent, true, 1);
                            
                            return true;
                        }
                    }
                }
                
                Console.WriteLine("无法通过发送鼠标点击事件获取坐标");
                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发送鼠标点击事件失败: {ex.Message}");
                return false;
            }
        });
    }

    /// <summary>
    /// 方法2: 通过VIP控制接口点击按钮
    /// </summary>
    /// <param name="browser">浏览器实例</param>
    /// <param name="selector">元素选择器</param>
    /// <returns>是否成功</returns>
    private async Task<bool> ClickByVIPControl(IFBroSharpBrowser browser, string selector)
    {
        return await Task.Run(() =>
        {
            try
            {
                // 首先通过JavaScript获取元素位置
                string jsCode = $@"
                    (function() {{
                        var element = document.querySelector('{selector}');
                        if (element) {{
                            var rect = element.getBoundingClientRect();
                            var centerX = rect.left + rect.width / 2;
                            var centerY = rect.top + rect.height / 2;
                            return centerX + ',' + centerY;
                        }}
                        return null;
                    }})();
                ";
                
                var callback = new FBroSharpJsCallbackSyn();
                browser.GetMainFrame().ExecuteJavaScriptToHasReturn(jsCode, default, default, callback);
                
                callback.help?.WaitEvent(5000);
                
                if (callback.help != null && callback.help.HavStringData())
                {
                    string coordinateData = callback.help.GetStringData();
                    
                    if (!string.IsNullOrEmpty(coordinateData) && coordinateData != "null")
                    {
                        string[] parts = coordinateData.Split(',');
                        if (parts.Length >= 2)
                        {
                            int x = (int)float.Parse(parts[0]);
                            int y = (int)float.Parse(parts[1]);
                            
                            Console.WriteLine($"VIP鼠标事件点击坐标: ({x}, {y})");
                            
                            // 使用VIP控制接口点击
                            using (var vip_control = browser.GetVIPControl())
                            {
                                var advanced = vip_control.GetAdvancedControl();
                                
                                // 先移动鼠标到目标位置
                                advanced.DispatchMouseMove(x, y);
                                Thread.Sleep(100);
                                
                                // 执行点击操作
                                advanced.DispatchMouseDown(x, y, 0);  // 按下左键
                                Thread.Sleep(50);
                                advanced.DispatchMouseUp(x, y, 0);    // 释放左键
                            }
                            
                            return true;
                        }
                    }
                }
                
                Console.WriteLine("无法通过VIP控制获取元素坐标");
                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"VIP鼠标事件失败: {ex.Message}");
                return false;
            }
        });
    }

    /// <summary>
    /// 增强版的上传按钮点击(支持多个选择器尝试)
    /// </summary>
    /// <param name="browser">浏览器实例</param>
    /// <param name="selectors">上传按钮的候选选择器数组</param>
    /// <returns>是否点击成功</returns>
    private async Task<bool> ClickUploadButtonAdvanced(IFBroSharpBrowser browser, string[] selectors = null)
    {
        // 默认的上传按钮选择器
        string[] defaultSelectors = {
            "input[type='file']",              // 标准文件输入框
            ".upload-button",                  // 通用上传按钮类
            "#fileUpload",                     // 常见的上传按钮ID
            ".file-upload-btn",               // 文件上传按钮类
            "button[data-action='upload']",    // 数据属性选择器
            ".btn-upload",                     // 上传按钮类
            "[role='button'][aria-label*='上传']", // ARIA标签选择器
            ".ant-upload",                     // Ant Design上传组件
            ".el-upload"                       // Element UI上传组件
        };
        
        string[] targetSelectors = selectors ?? defaultSelectors;
        
        foreach (string selector in targetSelectors)
        {
            Console.WriteLine($"尝试选择器: {selector}");
            
            if (await ClickUploadButton(browser, selector))
            {
                Console.WriteLine($"选择器 '{selector}' 点击成功");
                return true;
            }
            
            // 每次尝试之间稍作延迟
            await Task.Delay(500);
        }
        
        Console.WriteLine("所有上传按钮选择器都尝试失败");
        return false;
    }

    /// <summary>
    /// 等待上传完成
    /// </summary>
    private async Task<bool> WaitForUploadComplete(IFBroSharpBrowser browser, int timeoutMs = 30000)
    {
        var startTime = DateTime.Now;
        
        while ((DateTime.Now - startTime).TotalMilliseconds < timeoutMs)
        {
            // 检查是否有上传进度指示器
            string checkJs = @"
                var progressElement = document.querySelector('.upload-progress, .uploading, [class*=""upload""][class*=""progress""]');
                progressElement === null; // 返回true表示上传完成
            ";
            
            var callback = new FBroSharpJsCallbackSyn();
            browser.GetMainFrame().ExecuteJavaScriptToHasReturn(checkJs, default, default, callback);
            
            await Task.Run(() => callback.help.WaitEvent(3000));
            
            if (callback.help.HavBoolData() && callback.help.GetBoolData())
            {
                Console.WriteLine("上传进度检测完成");
                return true;
            }
            
            await Task.Delay(1000);
        }
        
        Console.WriteLine("等待上传完成超时");
        return false;
    }

    /// <summary>
    /// 验证是否为有效的图片文件
    /// </summary>
    private bool IsValidImageFile(string filePath)
    {
        if (!File.Exists(filePath))
        {
            return false;
        }
        
        string extension = Path.GetExtension(filePath).ToLower();
        return extension == ".jpg" || extension == ".jpeg" || 
               extension == ".png" || extension == ".gif" || 
               extension == ".bmp" || extension == ".webp";
    }

    /// <summary>
    /// 选择文件的实现(由OnFileDialog调用)
    /// </summary>
    public List<string> SelectFiles()
    {
        if (is_dragging && imageFiles.Count > 0)
        {
            Console.WriteLine($"自动选择 {imageFiles.Count} 个图片文件");
            return new List<string>(imageFiles);
        }
        
        return new List<string>();
    }
}

2. 文档批量上传示例

csharp
public class DocumentUploadManager
{
    private readonly Queue<string> uploadQueue = new Queue<string>();
    private bool is_uploading = false;

    /// <summary>
    /// 添加文档到上传队列
    /// </summary>
    /// <param name="documentPaths">文档路径列表</param>
    public void AddDocumentsToQueue(List<string> documentPaths)
    {
        foreach (string docPath in documentPaths)
        {
            if (IsValidDocument(docPath))
            {
                uploadQueue.Enqueue(docPath);
                Console.WriteLine($"文档已加入队列: {Path.GetFileName(docPath)}");
            }
        }
    }

    /// <summary>
    /// 批量上传文档
    /// </summary>
    /// <param name="browser">浏览器实例</param>
    /// <param name="uploadUrl">上传页面URL</param>
    public async Task<bool> BatchUploadDocuments(IFBroSharpBrowser browser, string uploadUrl)
    {
        try
        {
            is_uploading = true;
            int successCount = 0;
            int totalCount = uploadQueue.Count;
            
            Console.WriteLine($"开始批量上传 {totalCount} 个文档");
            
            while (uploadQueue.Count > 0)
            {
                string currentDoc = uploadQueue.Dequeue();
                
                // 设置当前要上传的文件
                var currentFiles = new List<string> { currentDoc };
                
                // 导航到上传页面
                browser.GetMainFrame().LoadURL(uploadUrl);
                await Task.Delay(2000);
                
                // 执行单个文件上传
                bool success = await UploadSingleDocument(browser, currentFiles);
                
                if (success)
                {
                    successCount++;
                    Console.WriteLine($"文档上传成功: {Path.GetFileName(currentDoc)} ({successCount}/{totalCount})");
                }
                else
                {
                    Console.WriteLine($"文档上传失败: {Path.GetFileName(currentDoc)}");
                }
                
                // 间隔等待,避免过快操作
                await Task.Delay(3000);
            }
            
            Console.WriteLine($"批量上传完成,成功: {successCount}/{totalCount}");
            return successCount == totalCount;
        }
        finally
        {
            is_uploading = false;
        }
    }

    /// <summary>
    /// 上传单个文档
    /// </summary>
    private async Task<bool> UploadSingleDocument(IFBroSharpBrowser browser, List<string> files)
    {
        // 这里实现具体的上传逻辑
        // 类似于前面的图片上传示例
        return true; // 简化示例
    }

    /// <summary>
    /// 验证是否为有效的文档文件
    /// </summary>
    private bool IsValidDocument(string filePath)
    {
        if (!File.Exists(filePath))
        {
            return false;
        }
        
        string extension = Path.GetExtension(filePath).ToLower();
        var validExtensions = new[] { ".pdf", ".doc", ".docx", ".txt", ".xls", ".xlsx", ".ppt", ".pptx" };
        
        return validExtensions.Contains(extension);
    }

    /// <summary>
    /// 获取当前上传状态的文件
    /// </summary>
    public List<string> SelectFiles()
    {
        if (is_uploading && uploadQueue.Count > 0)
        {
            // 返回队列中的下一个文件
            var nextFile = uploadQueue.Peek();
            return new List<string> { nextFile };
        }
        
        return new List<string>();
    }
}

最佳实践

1. 文件验证策略

csharp
public class FileValidationHelper
{
    /// <summary>
    /// 综合文件验证
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="maxSizeBytes">最大文件大小(字节)</param>
    /// <param name="allowedExtensions">允许的扩展名</param>
    /// <returns>验证结果</returns>
    public static FileValidationResult ValidateFile(string filePath, 
        long maxSizeBytes = 10 * 1024 * 1024, // 默认10MB
        string[] allowedExtensions = null)
    {
        var result = new FileValidationResult();
        
        try
        {
            // 1. 检查文件是否存在
            if (!File.Exists(filePath))
            {
                result.IsValid = false;
                result.ErrorMessage = "文件不存在";
                return result;
            }
            
            // 2. 检查文件大小
            var fileInfo = new FileInfo(filePath);
            if (fileInfo.Length > maxSizeBytes)
            {
                result.IsValid = false;
                result.ErrorMessage = $"文件大小超过限制 ({maxSizeBytes / 1024 / 1024}MB)";
                return result;
            }
            
            // 3. 检查文件扩展名
            if (allowedExtensions != null && allowedExtensions.Length > 0)
            {
                string extension = Path.GetExtension(filePath).ToLower();
                if (!allowedExtensions.Contains(extension))
                {
                    result.IsValid = false;
                    result.ErrorMessage = $"不支持的文件类型: {extension}";
                    return result;
                }
            }
            
            // 4. 检查文件是否被占用
            try
            {
                using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    // 文件可以正常打开
                }
            }
            catch (IOException)
            {
                result.IsValid = false;
                result.ErrorMessage = "文件被其他程序占用";
                return result;
            }
            
            result.IsValid = true;
            result.FileSize = fileInfo.Length;
            result.FileName = fileInfo.Name;
        }
        catch (Exception ex)
        {
            result.IsValid = false;
            result.ErrorMessage = $"文件验证出错: {ex.Message}";
        }
        
        return result;
    }
}

public class FileValidationResult
{
    public bool IsValid { get; set; }
    public string ErrorMessage { get; set; }
    public long FileSize { get; set; }
    public string FileName { get; set; }
}

2. 上传状态管理

csharp
public class UploadStateManager
{
    private readonly Dictionary<string, UploadStatus> uploadStates = new Dictionary<string, UploadStatus>();

    /// <summary>
    /// 设置文件上传状态
    /// </summary>
    public void SetUploadStatus(string filePath, UploadStatus status)
    {
        uploadStates[filePath] = status;
        Console.WriteLine($"文件 {Path.GetFileName(filePath)} 状态: {status}");
    }

    /// <summary>
    /// 获取所有上传状态
    /// </summary>
    public Dictionary<string, UploadStatus> GetAllUploadStates()
    {
        return new Dictionary<string, UploadStatus>(uploadStates);
    }

    /// <summary>
    /// 清理已完成的状态
    /// </summary>
    public void CleanupCompletedUploads()
    {
        var completedKeys = uploadStates
            .Where(kvp => kvp.Value == UploadStatus.Success || kvp.Value == UploadStatus.Failed)
            .Select(kvp => kvp.Key)
            .ToList();
            
        foreach (string key in completedKeys)
        {
            uploadStates.Remove(key);
        }
    }
}

public enum UploadStatus
{
    Pending,    // 等待上传
    Uploading,  // 正在上传
    Success,    // 上传成功
    Failed      // 上传失败
}

注意事项

1. 安全考虑

  • 文件路径验证:确保文件路径不包含恶意字符
  • 文件类型检查:严格验证文件扩展名和MIME类型
  • 文件大小限制:设置合理的文件大小上限
  • 病毒扫描:对于重要应用,考虑集成病毒扫描

2. 性能优化

  • 批量上传:合理控制并发上传数量
  • 内存管理:及时释放文件句柄和内存
  • 网络超时:设置合适的网络超时时间
  • 进度监控:提供上传进度反馈

3. 错误处理

  • 网络异常:处理网络连接问题
  • 文件锁定:处理文件被占用的情况
  • 权限问题:处理文件权限不足的问题
  • 重试机制:实现智能重试策略

调试建议

1. 日志记录

csharp
public static class UploadLogger
{
    public static void LogFileDialog(string action, string title, List<string> files)
    {
        Console.WriteLine($"[文件对话框] {action}");
        Console.WriteLine($"  标题: {title}");
        Console.WriteLine($"  文件数量: {files.Count}");
        
        foreach (string file in files)
        {
            Console.WriteLine($"  - {file}");
        }
    }
    
    public static void LogUploadProgress(string fileName, string status)
    {
        Console.WriteLine($"[上传进度] {fileName}: {status}");
    }
}

2. 状态监控

csharp
public void MonitorUploadState(IFBroSharpBrowser browser)
{
    string monitorJs = @"
        // 监控页面中的上传相关元素
        var uploadElements = document.querySelectorAll('[class*=""upload""], [id*=""upload""]');
        uploadElements.length + ' 个上传相关元素';
    ";
    
    var callback = new FBroSharpJsCallbackSyn();
    browser.GetMainFrame().ExecuteJavaScriptToHasReturn(monitorJs, default, default, callback);
    
    // 处理监控结果...
}

通过这些功能和最佳实践,您可以实现稳定可靠的自动化文件上传,无需用户手动操作文件对话框。

c#
private void button2_Click(object sender, EventArgs e)
{
    is_dragging = true;
    FBroSharpFileDialogCallbackDis callback = new FBroSharpFileDialogCallbackDis();
    BrowserList.data[0].RunFileDialog(FBroSharpFileDialogModeType.FILE_DIALOG_OPEN, "打开对话框", Directory.GetCurrentDirectory(), default, callback);
}

public List<string> SelectFiles()
{
    if (is_dragging)
    {
        return new List<string>() { "C:\\Users\\mosheng\\Downloads\\打开文件选择对话框.gif", "C:\\Users\\mosheng\\Downloads\\微信图片_20250214222652.png" };
    }
    else
    {
        return new List<string>();
    }
    
}

2、BrowserEvent.cs浏览器_即将打开对话框事件中的对话框回调IFBroSharpFileDialogEventCallback设置上传的图片即可实现浏览器不会打开文件对话框,自动选择文件

c#
//浏览器_即将打开对话框
public override bool OnFileDialog(IFBroSharpBrowser browser, 
    FBroSharpFileDialogModeType mode, 
    string title, 
    string default_file_path, 
    out List<string> accept_filters, 
    IFBroSharpFileDialogEventCallback callback)
{
     accept_filters = new List<string>();
    // 添加文件过滤器模式
    accept_filters.Add("Text Files (*.txt)|*.txt");

    //手动指定选择的文件
    List<string> select_filters = new List<string>();


    select_filters = _form.SelectFiles();
    callback.Continue(select_filters);
    if (select_filters.Count > 0)
    {
        callback.Continue(select_filters);
        return true;
    }
    else
    {
        callback.Dispose();
        return false;
    }
}

如果文档对您有帮助,欢迎 请喝咖啡 ☕ | 软件发布 | 源码购买