一、CefSharp文件下载分析

查看ChromiumWebBrowser类发现cef数据下载处理在IDownloadHandler中进行,但并未找到相应的实现类,故我们需要自己实现DownloadHandler

创建CustomDownloadHandler类并实现IDownloadHandler接口

public class CustomDownloadHandler : IDownloadHandler
{
public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem,
IBeforeDownloadCallback callback)
{
throw new System.NotImplementedException();
} public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem,
IDownloadItemCallback callback)
{
throw new System.NotImplementedException();
}
}

IDownloadHandler中声明了两个方法,从方法命名来看 OnBeforeDownload和OnDownloadUpdated一个是在下载之前处理,一个在下载中处理

1、首先看第一个方法OnBeforeDownload

DownloadItem 类如下图这里给我们提供了下载文件的相关信息(文件建议名称、源地址、文件大小、当前大小等)

查看IBeforeDownloadCallback接口定义

IsDisposed 判断当前下载回调对象是否已释放

Continue 继续下载 第一个参数为下载路径、第二个数是否弹出保存对话框

2、接下来我们看 OnDownloadUpdated

方法中 DownloadItem 与 OnBeforeDownload中相同

再看回调接口 IDownloadItemCallback ,提供了取消下载、暂停下载、继续下载等方法

3、综上所述

CefSharp下载前的设置可以在 OnBeforeDownload中进行处理

下载的实时状态可以在 OnDownloadUpdated进行处理

二、通知外部正在下载文件

当文件下载时我们需要通知浏览器显示下载工具栏并更新下载状态信息

在 CustomDownloadHandler中新增_downloadCallBackEvent事件

private readonly Action<bool, DownloadItem> _downloadCallBackEvent;//第一个参数为true为update

第一个参数判断在OnBeforeDownload还是在OnDownloadUpdated中执行

public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem,
IBeforeDownloadCallback callback)
{
if (callback.IsDisposed) return;
_downloadCallBackEvent?.Invoke(false, downloadItem);
downloadItem.IsInProgress = true;
var path = GetDownloadFullPath(downloadItem.SuggestedFileName);
callback.Continue(path, false);
} public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem,
IDownloadItemCallback callback)
{
_downloadCallBackEvent?.Invoke(true, downloadItem);
}

三、设计下载任务栏

上图为Edge下载任务栏

据图可以分为三个部分,红框部分存在一个或多个,两个绿框部分为固定部分

创建 UserControl 【DownloadToolUc】 暂根据上图设计UI如下

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" x:Name="ItemsParent" Orientation="Horizontal" HorizontalAlignment="Left"> </StackPanel>
<Button Grid.Column="1" Style="{DynamicResource Button.DownloadLookAllButton}" Content="全部显示" Click="ShowAll_OnClick"/>
<Button Grid.Column="2" Style="{DynamicResource Button.DownloadCloseButton}" Margin="5,0" Click="CloseDownloadTool_OnClick"/>
</Grid>

红框部分单独创建UserControl 【DownloadToolItemUc】

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Margin="10,0" Source="{DynamicResource DrawingImage.File}" Width="25" Height="25"/>
<StackPanel Grid.Column="1" HorizontalAlignment="Left">
<TextBlock Text="{Binding FileName}" FontSize="14" Margin="0,5,0,0" TextTrimming="CharacterEllipsis"/>
<Grid>
<TextBlock Margin="0,5,0,0" Visibility="Collapsed">
<Hyperlink FontSize="14" Foreground="{DynamicResource WebBrowserBrushes.OpenFileForeground}" Focusable="False" Click="OpenFile_OnClick">打开文件</Hyperlink>
</TextBlock>
<StackPanel Margin="0,5,0,0">
<ProgressBar Height="6"/>
<TextBlock FontSize="12" Margin="0,5,0,0" TextTrimming="CharacterEllipsis">
<Run Text="{Binding CurrentSizeStr}"/>
<Run Text="/"/>
<Run Text="{Binding TotalSizeStr}"/>
</TextBlock>
</StackPanel>
</Grid>
</StackPanel>
<Button Grid.Column="2" Style="{DynamicResource Button.DownloadLookAllButton}" Width="35" Height="35" Content=". . ." Padding="0,0,0,9" Margin="10,0,5,0"/>
</Grid>

四、下载绑定处理

1、为DownloadToolItemUc添加ViewModel

 public class DownloadToolItemViewModel : BaseViewModel
{
private string _currentSizeStr;
public string CurrentSizeStr { get => _currentSizeStr; set { _currentSizeStr = value; OnPropertyChanged("CurrentSizeStr"); } } private string _totalSizeStr;
public string TotalSizeStr { get => _totalSizeStr; set { _totalSizeStr = value; OnPropertyChanged("TotalSizeStr"); } } private string _fileName;
public string FileName { get => _fileName; set { _fileName = value; OnPropertyChanged("FileName"); } } public string ConvertFileSize(long size)
{
if (size > 1024 * 1024 * 1024)
{
return $"{size / (1024 * 1024 * 1024)}G";
}
if (size > 1024 * 1024)
{
return $"{size / (1024 * 1024)}M";
}
return size > 1024 ? $"{size / 1024}K" : $"{size}B";
}
}

2、在DownloadToolUc中增加 DownloadFile方法

public void DownloadFile(bool isUpdate, DownloadItem downloadItem)
{
if (!isUpdate)
{
if (_downloadDict.ContainsKey(downloadItem.Id)) return;
var viewModel = new DownloadToolItemViewModel
{
FileName = downloadItem.SuggestedFileName,
};
_downloadDict.Add(downloadItem.Id, viewModel); this.Dispatcher.Invoke(new Action(() =>
{
this.Visibility = Visibility.Visible;
var item = new DownloadToolItemUc { DataContext = viewModel };
ItemsParent.Children.Insert(0, item);
})); }
else
{
if (!_downloadDict.ContainsKey(downloadItem.Id)) return;
var item = _downloadDict[downloadItem.Id];
item.CurrentSizeStr = item.ConvertFileSize(downloadItem.ReceivedBytes);
item.TotalSizeStr = downloadItem.TotalBytes <= 0 ? "未知" : item.ConvertFileSize(downloadItem.TotalBytes);
}
}

3、在创建新TabItem时建立回调事件与DownloadFile绑定

var uc = new WebTabItemUc { ViewModel = { CurrentUrl = obj?.ToString() } };
uc.CefWebBrowser.DownloadCallBackEvent += DownloadTool.DownloadFile;

五、下载进度绑定

在DownloadToolItemViewModel 中增加如下两个属性

private double _currentSize;
public double CurrentSize { get => _currentSize; set { _currentSize = value; OnPropertyChanged("CurrentSize"); } } private double _totalSize;
public double TotalSize { get => _totalSize; set { _totalSize = value; OnPropertyChanged("TotalSize"); } }

在DownloadToolItemUc控件中绑定

<ProgressBar Height="6" Maximum="{Binding TotalSize}" Value="{Binding CurrentSize}"/>

注意在给ViewModel赋值时downloadItem.TotalBytes可能为0,故增加TotalSize增加如下处理

item.TotalSize = downloadItem.TotalBytes > downloadItem.ReceivedBytes? downloadItem.TotalBytes : downloadItem.ReceivedBytes;
item.CurrentSize = downloadItem.ReceivedBytes;

六、下载栏增加显隐动画

任务栏的显示和隐藏有些突兀,为了显示丝滑一些,为其增加简单关键帧动画

为 DownloadToolUc增加 RenderTransform特效 并定义Storyboard资源如下

    <UserControl.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform Y="50"/>
</TransformGroup>
</UserControl.RenderTransform>
<Grid Background="{DynamicResource WebBrowserBrushes.DownloadToolBackground}" x:Name="ParentGrid">
<Grid.Resources>
<!-- 显示下载工具栏 -->
<Storyboard x:Key="DisplayTool" RepeatBehavior="1x">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="DownloadUc">
<EasingDoubleKeyFrame Value="0" KeyTime="00:00:01">
<EasingDoubleKeyFrame.EasingFunction>
<QuarticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard> <Storyboard x:Key="HideTool" RepeatBehavior="1x">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="DownloadUc">
<EasingDoubleKeyFrame Value="50" KeyTime="00:00:01">
<EasingDoubleKeyFrame.EasingFunction>
<QuarticEase EasingMode="EaseInOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>

此处我们使用TranslateTransform(平移动画) <TranslateTransform Y="50"/> 意味着初始时距离0,0点向下50

显示下载工具栏时使纵坐标回到0点,隐藏时使纵坐标到达50

在cs文件中增加动画启动方法

private void InitStoryboard()
{
_displayToolStoryboard = (Storyboard)ParentGrid.FindResource("DisplayTool");
_hideToolStoryboard = (Storyboard)ParentGrid.FindResource("HideTool");
} private void DisplayTool()
{
_displayToolStoryboard.Begin();
} private void HideTool()
{
_hideToolStoryboard.Begin();
}

在下载时执行DisplayTool 在关闭时执行HideTool

七、源码地址

gitee地址:https://gitee.com/sirius_machao/mweb-browser

基于CefSharp开发(四)浏览器文件下载的更多相关文章

  1. 基于CefSharp开发浏览器(八)浏览器收藏夹栏

    一.前言 上一篇文章 基于CefSharp开发(七)浏览器收藏夹菜单 简单实现了部分收藏夹功能 如(添加文件夹.添加收藏.删除.右键菜单部分功能) 后续代码中对MTreeViewItem进行了扩展,增 ...

  2. mac 下基于firebreath 开发多浏览器支持的浏览器插件

    mac 下基于firebreath 开发多浏览器支持的浏览器插件 首先要区分什么是浏览器扩展和浏览器插件;插件可以像本地程序一样做的更多 一. 关于 firebreath http://www.fir ...

  3. 基于CefSharp开发(二)自定义浏览器窗体

    上一篇 https://www.cnblogs.com/mchao/p/13914726.html 简单了解了CefSharp引用配置但页面光秃秃的,这一篇着手开发简单浏览器窗体 一.Edge浏览器窗 ...

  4. 基于CefSharp开发(五)浏览器菜单样式

    一.菜单分析 上图为Edge浏览器现有的菜单内容,菜单中即有子菜单也有组合菜单. 本章节将开发浏览器菜单样式,菜单部分功能将后期进行处理. 二.创建菜单用户控件 新建用户控件命名为WebMenuUc, ...

  5. 基于CefSharp开发(三)浏览器头部优化

    一.上文回顾 上编实现了简单的网页加载功能包括URL输入.打开空标签页.网页链接中新页面处理等 本编将对网页的Title绑定.前进.后退.刷新等事件处理 二.Title绑定处理 当打开网页时Title ...

  6. 基于CefSharp开发(七)浏览器收藏夹菜单

    一.Edge收藏夹菜单分析 如下图所示为Edge收藏夹菜单, 点击收藏夹菜单按钮(红框部分)弹出收藏夹菜单窗体,窗体中包含工具栏(绿框部分)和树型菜单(黄框部分) 工具栏按钮功能分别为添加当前网页到根 ...

  7. 基于CefSharp开发浏览器(九)浏览器历史记录弹窗面板

    一.前言 前两篇文章写的是关于浏览器收藏夹的内容,因为收藏夹的内容不会太多,故采用json格式的文本文件作为收藏夹的存储方式. 关于浏览器历史记录,我个人每天大概会打开百来次网页甚至更多,时间越长历史 ...

  8. 基于CefSharp开发(六)浏览器网页缩放

    一.网页缩放分析 缩放入口 1.Ctrl + 鼠标滑轮缩放 2.菜单中缩放子菜单缩放 3.搜索框中网页缩放按钮缩放 缩放属性及命令 ChromiumWebBrowser 提供了缩放量值.缩放级别.放大 ...

  9. 基于cefsharp的用户浏览器

    技术:vc++2015   概述 用于需要制作一个浏览器 winfrom 中浏览器的插件有很多种 如:WebBrowser , Web.kit等 但用于比较稳定 功能齐全的还是cefsharp 详细 ...

随机推荐

  1. 修改redo log 的大小

    alert日志中含有大量警告信息:"Thread 1 cannot allocate new log, sequence 320xx Checkpoint not complete" ...

  2. linux 的mysql 主从备份

    1.原理 mysql主从配置的流程大体如图: 1)master会将变动记录到二进制日志里面: 2)master有一个I/O线程将二进制日志发送到slave; 3) slave有一个I/O线程把mast ...

  3. openssl ec/ecparam/errstr/ripemd160/camellia-128-ecb/camellia-192-cbc/camellia-192-ecb3条指令及1个哈希算法3个加密算法的学习

    ecparam ecparam指令通过用椭圆曲线加密方式,生成ec密钥,可以指定参数 openssl ecparam [-inform DER|PEM] [-outform DER|PEM] [-in ...

  4. 3.2 表 ADT -3.3 Java Collection API 中的表

    3.2 表 ADT 处理形如 A0, A1, A2, --, AN-1 的一般的表.我们称这个表大小为N.将大小为0的特殊表称为空表 对于除空表以外的任何表,称 Ai-1 前驱 Ai,Ai 后继 Ai ...

  5. Unknown CMake command

    Unknown CMake command "add_clang_library".等 在官网上照着打 发现上面错误 结果是版本问题 选好版本和选项catkin还是rosbuild

  6. Android Google官方文档解析之——Device Compatibility

    Android is designed to run on many different types of devices, from phones to tablets and television ...

  7. codeforces 1425E,一万种情况的简单题

    大家好,欢迎阅读codeforces专题. 我们今天选中的是codeforces 1425场比赛的E题,这是一场印尼多校联合的ICPC的练习赛.ACM赛制,难度也比较近似.我们今天选择的是其中的一道M ...

  8. C++ 基础 3:类和对象

    1 类和对象 1.1 类定义 类定义是以关键字 class 开头,后跟类的名称.类的主体是包含在一对花括号中.类定义后必须跟着一个分号或一个声明列表.例如,我们使用关键字 class 定义 Box 数 ...

  9. binary hacks读数笔记(readelf基本命令)

    一.首先对readelf常用的参数进行简单说明: readelf命令是Linux下的分析ELF文件的命令,这个命令在分析ELF文件格式时非常有用,下面以ELF格式可执行文件test为例详细介绍: 1. ...

  10. shell中数字、字符串、文件比较测试

    1.逻辑运算符:与&&     或||    非!  &&:双目操作符:与运算中:如果第一个数为假,结果一定为假   ==> 短路操作符 ||:双目操作符:或运算 ...