基于CefSharp开发(二)自定义浏览器窗体
上一篇 https://www.cnblogs.com/mchao/p/13914726.html 简单了解了CefSharp引用配置但页面光秃秃的,这一篇着手开发简单浏览器窗体
一、Edge浏览器窗体分析

如上图所示可先将浏览器窗体分为两大部分,Header及Body部分,Header暂时分为Tab展示及搜索部分 每个Tab页有一个搜索及ChromiumWebBrowser
此时我们需要一个带关闭按钮的TabControl
二、自定义TabControl
修改TabItem ControlTemplate增加Button,关于TabControl分析请参考 Cys_Control(四) MTabControl
<Button Grid.Column="1" Style="{StaticResource TabCloseButton}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MTabControl}},Path=TabItemRemoveCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}" />
CommandParamenter 参数传当前 TabItem
在cs文件中添加依赖属性TabItemRemoveCommand
public static readonly DependencyProperty TabItemRemoveCommandProperty = DependencyProperty.Register("TabItemRemoveCommand", typeof(ICommand), typeof(MTabControl), new PropertyMetadata(null));
public ICommand TabItemRemoveCommand
{
get => (ICommand)GetValue(TabItemRemoveCommandProperty);
set => SetValue(TabItemRemoveCommandProperty, value);
}
并为TabItemRemoveCommand添加移除方法
private void TabItemRemove(object obj)
{
if (obj is TabItem item)
{
this.Items.Remove(item);
}
}
有了移除还需要有新增

在 TabControl中添加 Button,原理同移除
<Button Grid.Column="1" Style="{StaticResource TabAddButton}" HorizontalAlignment="Left"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MTabControl}},Path=TabItemAddCommand}"/>

三、添加搜索框

由图可知 Edge 搜索框由 三部分组成即(左右按钮及中间文本),相当于TextBox中增加了俩按钮,因此我们对TextBox做个扩展
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Button Style="{DynamicResource Button.NavigationSearch}" Margin="2,0"/>
</Grid>
<Grid Grid.Column="1">
<ScrollViewer x:Name="PART_ContentHost" FontSize="{TemplateBinding FontSize}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" BorderThickness="0" IsTabStop="False"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="4,0"/>
<!--水印-->
<TextBlock x:Name="Part_Watermark" Text="{TemplateBinding Watermark}" FontSize="{TemplateBinding FontSize}" Visibility="Hidden" HorizontalAlignment="Left"
Foreground="{DynamicResource ColorBrush.FontWatermarkColor}" IsHitTestVisible="False" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="5,0"/>
</Grid>
<Grid Grid.Column="2">
<ToggleButton Style="{DynamicResource ToggleButton.NavigationCollection}" Margin="2,0"/>
</Grid>
</Grid>
文本框中左边增加Button,右边增加ToggleButton来区分是否网页已收藏(注:本次不加入业务处理)
关于TextBox水印及其他处理 请参照 Cys_Control(三) MTextBox

四、调整布局
增加前进回退刷新等按钮用于占位并调整搜索框
<Grid Grid.Row="0" Background="{DynamicResource WebBrowserBrushes.TabHeaderIsSelectedBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<Button Style="{DynamicResource Button.NavigationBack}"/>
<Button Style="{DynamicResource Button.NavigationForward}"/>
<Button Style="{DynamicResource Button.NavigationRefresh}"/>
</StackPanel>
<controls:MTextBox Grid.Column="1" Watermark="搜索或输入Web地址" x:Name="SearchText"/>
<Grid Grid.Column="2" MinWidth="150">
</Grid>
</Grid>

此时从页面上看已经有些像浏览器了,跑起来。。。

此时发现点击网页链接和预想的打开新Tab页有些差距
五、新Tab页打开链接
Cef的Popup处理定义在ILifeSpanHandler接口中,若要阻止弹窗并使用自己的Tab页则应该自定义LifeSpanHandler
新增CustomLifeSpanHandler类并实现ILifeSpanHandler接口
public class CustomLifeSpanHandler : ILifeSpanHandler
{
public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl,
string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures,
IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
{
if (chromiumWebBrowser is CustomWebBrowser webBrowser)
{
webBrowser.OpenNewTab(targetUrl);
}
newBrowser = null;
return true;
} public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser)
{ } public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
{
return false;
} public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
{ }
}
OnBeforePopup方法中可以取到 targetUrl也就是点击的<a>标签中的链接
此时我们需要将targetUrl传递到WebBrowser中,由于我们需要打开Tab页,需要增加一个方法 OpenNewTab(targetUrl),
ChromiumWebBrowser类并不能满足我们的使用场景,故扩展ChromiumWebBrowser类,新增CustomWebBrowser继承于ChromiumWebBrowser
并添加 OpenNewTab方法
public void OpenNewTab(string url)
{
Dispatcher.Invoke(() =>
{
var tabControl = ControlHelper.FindVisualParent<MTabControl>(this);
tabControl?.TabItemAddCommand?.Execute(url);
});
}
该方法用于新增一个Tab页。
运行看效果

六、源码地址
gitee地址:https://gitee.com/sirius_machao/mweb-browser
基于CefSharp开发(二)自定义浏览器窗体的更多相关文章
- 基于.net开发chrome核心浏览器【二】
原文:基于.net开发chrome核心浏览器[二] 一: 上一篇的链接: 基于.net开发chrome核心浏览器[一] 二: 相关资源介绍: chrome Frame: 让IE有一颗chrome的心, ...
- 基于CefSharp开发浏览器(八)浏览器收藏夹栏
一.前言 上一篇文章 基于CefSharp开发(七)浏览器收藏夹菜单 简单实现了部分收藏夹功能 如(添加文件夹.添加收藏.删除.右键菜单部分功能) 后续代码中对MTreeViewItem进行了扩展,增 ...
- 基于.net开发chrome核心浏览器【七】
这是一个系列的文章,前面六篇文章的地址如下: 基于.net开发chrome核心浏览器[六] 基于.net开发chrome核心浏览器[五] 基于.net开发chrome核心浏览器[四] 基于.net开发 ...
- 基于.net开发chrome核心浏览器
本文转载自:http://www.cnblogs.com/liulun/archive/2013/04/20/3031502.html 一: 上一篇的链接: 基于.net开发chrome核心浏览器[一 ...
- 基于.net开发chrome核心浏览器【四】
原文:基于.net开发chrome核心浏览器[四] 一: 上周去北京出差,给国家电网的项目做架构方案,每天都很晚睡,客户那边的副总也这样拼命工作. 累的不行了,直接导致第四篇文章没有按时发出来. 希望 ...
- 基于.net开发chrome核心浏览器【三】
原文:基于.net开发chrome核心浏览器[三] 本篇我们讲解怎么用CefGlue开发一个最简单的浏览器 一: CefGlue是建立在Cef项目之上的,Cef项目是C/C++的项目:CefGlue只 ...
- 基于.net开发chrome核心浏览器【一】
原文:基于.net开发chrome核心浏览器[一] 说明: 这是本系列的第一篇文章,我会尽快发后续的文章. 源起 1.加快葬送IE6浏览器的进程 世界上使用IE6浏览器最多的地方在中国 中国使用IE6 ...
- 基于.net开发chrome核心浏览器【五】
一:本篇将解决的问题 本章主要为了解决一下几个问题: 1.JsDialog的按钮错位的问题 我们开发出的浏览器,在有些操系统上调用alert,confirm之类的对话框时,确定和取消按钮会出现错位的情 ...
- 基于CefSharp开发(五)浏览器菜单样式
一.菜单分析 上图为Edge浏览器现有的菜单内容,菜单中即有子菜单也有组合菜单. 本章节将开发浏览器菜单样式,菜单部分功能将后期进行处理. 二.创建菜单用户控件 新建用户控件命名为WebMenuUc, ...
随机推荐
- python开发--python函数-(持续更新)
1. 打印 : print() # 打印,输出 2. 变量 : var = 'hello' # 变量var , 把'hello' 赋值给变量 var 3. if 函数 : # 代码块 4个空格或者一个 ...
- Mongoose Guide(转)
转自:http://www.w3c.com.cn/mongoose-guide Queries 文件可以通过一些静态辅助模型的方法检索. 任何涉及 指定 查询 条件的模型方法,有两种执行的方式: 当一 ...
- Go语言如何像foreach一样有序遍历map
目录 问题 解决 给key排序思路 开源实现 问题 Go语言的Map是无序遍历的,遍历一个map代码如下 package main import ( "fmt" ) func ma ...
- 重温Java泛型,带你更深入地理解它,更好的使用它!
1. 引言 jdk5.0中引入了Java泛型,目的是减少错误,并在类型上添加额外的抽象层. 本文将简要介绍Java中的泛型.泛型背后的目标以及如何使用泛型来提高代码的质量. 2. 为什么要用泛型? 设 ...
- Oracle数据库操作相关
1. 导出dmp 文件 (1)导出数据库所有的用户数据: exp system/manage@ORCL file=D:\oracle_dmp\data1.dmp full=y (2)导出指定的用户数据 ...
- jdk的动态代理和静态代理你还写不出来嘛???
一.什么叫jdk的代理? 用另外一个对象去代理实际对象的操作 分为动态代理和静态代理二.先说说静态代理 从字面意思来看就是不会改变的,只可以代理某个固定对象的. 静态代理就是通过实现和目标对象实现的同 ...
- dpdk网卡收包分析
一个网络报文从网卡接收到被应用处理,中间主要需要经历两个阶段: 阶段一:网卡通过其DMA硬件将收到的报文写入到收包队列中(入队)阶段二:应用从收包队列中读取报文(出队)由于目前正在使用vpp/dpdk ...
- nginx&http 第三章 ngx HTTP 请求的 11 个处理阶段
nginx 将一个 HTTP 请求分为 11 个处理阶段,这样做让每一个 HTTP 模块可以仅仅专注于完成一个独立.简单的功能,而一个请求的完整处理过程可以由多个 HTTP 模块共同合作完成将一次 H ...
- socket connect tcp_v4_connect
tcp_v4_connect /* This will initiate an outgoing connection. tcp_v4_connect函数初始化一个对外的连接请求,创建一个SYN包并发 ...
- ubuntu13.04修改默认启动内核
ubuntu下面的启动内核选项跟其他操作系统不一样,有个子菜单,比如我在默认的ubuntu13.04上安装了一个新的内核3.14.5,那么默认的第一项是3.14.5内核,第二项是一个子菜单,第二项里面 ...