基于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, ...
随机推荐
- Kubernetes-17:Kubernets包管理工具—>Helm介绍与使用
Kubernets包管理工具->Helm 什么是Helm? 我们都知道,Linux系统各发行版都有自己的包管理工具,比如Centos的YUM,再如Ubuntu的APT. Kubernetes也有 ...
- 知识补充之Django信号量
信号 抛砖引玉 1.如何对数据库的增加操作记录日志 2.信号比中间件的区别 Django中提供了"信号调度",用于在框架执行操作时解耦.通俗来讲,就是一些动作发生的时候,信号允许特 ...
- js数组方法(管饱)
有一些数组方法是ECMAScript新增的,一定要注意浏览器的兼容!! Array对象属性: 属性 说明 constructor 返回对创建此对象的函数引用 length 返回集合内的元素的所有长度 ...
- MySQL全面瓦解11:子查询和组合查询
概述 子查询是SQL查询中的重要一块,是我们基于多表之间进行数据聚合和判断的一种手段,使得我们的处理复杂数据更加的便捷,这一节我们主要来了解一下子查询. 先做一下数据准备,这边建立三张表:班级.学生. ...
- TCP回射客户服务器模型(01 socket bind listen accept connect)
socket函数(安装电话机)头文件:#include<sys/socket.h> int socket(int family, int type, int protocol); //返 ...
- 利用虚拟化环境虚拟nvme盘
前情介绍 SPDK SPDK的全称为Storage Performance Development Kit ,是Intel发起的一个开源驱动项目,这个是一个开发套件,可以让应用程序在用户态去访问存储资 ...
- Map结合Function函数式接口的巧妙之处
需求:在给定 List 集合中,需根据不同的算法规则,选取计算方式并返回结果: 例如:[1, 2, 3, 4, 5] List 集合中都是 Integer 类型数据,根据提供的算法规则,sum 求和, ...
- LeetCode 中等题解(2)
31 下一个排列 Question 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须 ...
- Dnscat2实现DNS隐蔽隧道反弹Shell
DNS介绍 DNS是域名系统(Domain Name System)的缩写,是因特网的一项核心服务,它作为可以将域名和IP地址相互映射的一个分布式数据库,能够使人更方便的访问互联网,而不用去记住能够被 ...
- springboot中使用Filter、Interceptor和aop拦截REST服务
在springboot中使用rest服务时,往往需要对controller层的请求进行拦截或者获取请求数据和返回数据,就需要过滤器.拦截器或者切片. 过滤器(Filter):对HttpServletR ...