一、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. 关于Java中泛型、反射和注解的扫盲篇

    泛型 泛型概念   泛型是在JDK1.5之后引入的,旨在让我们写出更加通用化,更加灵活的代码.通用化的手段在于让数据类型变得参数化,定义泛型时,对应的数据类型是不确定的,泛型方法被调用时,会指定具体类 ...

  2. dat.GUI 打造可视化工具(一)

    前言 有时候学习api其实我们可以从源码的角度学习,因为有时候很多文档写的太不清楚了,自己都是慢慢去试,去猜,去实现其实也是挺浪费时间的,面对未知的一脸蒙蔽,偶尔烦躁,其实需要的是自己静下心来慢慢研究 ...

  3. linux + MongoDB 安装 + 部署 + 讲解 (满满干货看完记得收藏噢)

    话不多说开始了! 安装 安装就依据菜鸟教程的进行安装 传送门 => https://www.runoob.com/mongodb/mongodb-linux-install.html 好啦!现在 ...

  4. python的数据处理一

    def load_data(filename): features = [] labels = [] f = open(filename, encoding='utf-8') medical = js ...

  5. Pandas_VBA_数据清洗对比

    VBA处理数据与Python Pandas处理数据案例比较 Author : Collin_PXY 需求: 现有一个 csv文件,包含'CNUM'和'COMPANY'两列,数据里包含空行,且有内容重复 ...

  6. linux c语言 哲学家进餐---信号量PV方法一

    1.实验原理   由Dijkstra提出并解决的哲学家进餐问题(The Dinning Philosophers Problem)是典型的同步问题.该问题是描述有五个哲学家共用一张圆桌,分别坐在周围的 ...

  7. 【django】长轮询

    API.PY import queue from django.contrib.auth.hashers import check_password from rest_framework.views ...

  8. linux Netfilterr中扩展match target

    Match: netfilter定义了一个通用的match数据结构struct xt_match /* 每个struct xt_match代表一个扩展match,netfilter中各个扩展match ...

  9. binary hacks读数笔记(objdump命令)

    一.首先看一下几个常用参数的基本含义: objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,它还有其他作用,下面以ELF格式可执行文件test为例详细介绍: 1.objdump -f ...

  10. spring中的数据库操作类

    例子一: package cn.itcast.service.impl; import java.util.List; import javax.sql.DataSource; import org. ...