基于CefSharp开发(四)浏览器文件下载
一、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开发(四)浏览器文件下载的更多相关文章
- 基于CefSharp开发浏览器(八)浏览器收藏夹栏
一.前言 上一篇文章 基于CefSharp开发(七)浏览器收藏夹菜单 简单实现了部分收藏夹功能 如(添加文件夹.添加收藏.删除.右键菜单部分功能) 后续代码中对MTreeViewItem进行了扩展,增 ...
- mac 下基于firebreath 开发多浏览器支持的浏览器插件
mac 下基于firebreath 开发多浏览器支持的浏览器插件 首先要区分什么是浏览器扩展和浏览器插件;插件可以像本地程序一样做的更多 一. 关于 firebreath http://www.fir ...
- 基于CefSharp开发(二)自定义浏览器窗体
上一篇 https://www.cnblogs.com/mchao/p/13914726.html 简单了解了CefSharp引用配置但页面光秃秃的,这一篇着手开发简单浏览器窗体 一.Edge浏览器窗 ...
- 基于CefSharp开发(五)浏览器菜单样式
一.菜单分析 上图为Edge浏览器现有的菜单内容,菜单中即有子菜单也有组合菜单. 本章节将开发浏览器菜单样式,菜单部分功能将后期进行处理. 二.创建菜单用户控件 新建用户控件命名为WebMenuUc, ...
- 基于CefSharp开发(三)浏览器头部优化
一.上文回顾 上编实现了简单的网页加载功能包括URL输入.打开空标签页.网页链接中新页面处理等 本编将对网页的Title绑定.前进.后退.刷新等事件处理 二.Title绑定处理 当打开网页时Title ...
- 基于CefSharp开发(七)浏览器收藏夹菜单
一.Edge收藏夹菜单分析 如下图所示为Edge收藏夹菜单, 点击收藏夹菜单按钮(红框部分)弹出收藏夹菜单窗体,窗体中包含工具栏(绿框部分)和树型菜单(黄框部分) 工具栏按钮功能分别为添加当前网页到根 ...
- 基于CefSharp开发浏览器(九)浏览器历史记录弹窗面板
一.前言 前两篇文章写的是关于浏览器收藏夹的内容,因为收藏夹的内容不会太多,故采用json格式的文本文件作为收藏夹的存储方式. 关于浏览器历史记录,我个人每天大概会打开百来次网页甚至更多,时间越长历史 ...
- 基于CefSharp开发(六)浏览器网页缩放
一.网页缩放分析 缩放入口 1.Ctrl + 鼠标滑轮缩放 2.菜单中缩放子菜单缩放 3.搜索框中网页缩放按钮缩放 缩放属性及命令 ChromiumWebBrowser 提供了缩放量值.缩放级别.放大 ...
- 基于cefsharp的用户浏览器
技术:vc++2015 概述 用于需要制作一个浏览器 winfrom 中浏览器的插件有很多种 如:WebBrowser , Web.kit等 但用于比较稳定 功能齐全的还是cefsharp 详细 ...
随机推荐
- Swagger 3.0 天天刷屏,真的香吗?
持续原创输出,点击上方蓝字关注我 目录 前言 官方文档如何说? Spring Boot版本说明 添加依赖 springfox-boot-starter做了什么? 撸起袖子就是干? 定制一个基本的文档示 ...
- 【Kata Daily 190909】The Supermarket Queue(超市队列)
题目: There is a queue for the self-checkout tills at the supermarket. Your task is write a function t ...
- 回顾MySql的一些基本的增删改查
---恢复内容开始--- 回顾数据库的一些简单的增删查改的操作语法与注意点,来自菜鸟教程https://www.runoob.com/mysql/mysql-tutorial.html 关于数据库的操 ...
- 利用GitHub和Hexo打造免费的个人博客
每个程序猿都需要一个个人博客,目前广泛出现在大家视野里的有CSDN.博客园.简书,但是他们却没有给用户一个专属的站点.一个好记的域名.你需要一个https://xxx.xxx.xxx/格式的网址,一个 ...
- nginx&http 第二章 ngx 事件event初始化 ngx_event_process_init
|----------(ngx_worker_process_cycle->ngx_worker_process_init) |--------->for(;;) {ngx_process ...
- python之《tkinter》
1.创建窗口 import tkinter as tk window = tk.Tk() window.title('my window') window.geometry('300x100') -- ...
- AQS详解,并发编程的半壁江山
千呼万唤始出来,终于写到AQS这个一章了,其实为了写这一章,前面也是做了很多的铺垫,比如之前的 深度理解volatile关键字 线程之间的协作(等待通知模式) JUC 常用4大并发工具类 CAS 原子 ...
- spring cloud 入门系列
springcloud入门总结转发自:https://www.cnblogs.com/sam-uncle/p/9340390.html 最近看到微服务很火,也是未来的趋势, 所以就去学习下,在dubb ...
- 分布式 task_master / task_worker
17:08:0317:08:04 在Thread(线程)和Process(进程)中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分 ...
- 2、Spring Boot配置
1.配置文件 SpringBoot使用一个全局的配置文件,配置文件名是固定的: •application.properties •application.yml 配置文件的作用:修改SpringBoo ...