一、前言

前两篇文章写的是关于浏览器收藏夹的内容,因为收藏夹的内容不会太多,故采用json格式的文本文件作为收藏夹的存储方式。

关于浏览器历史记录,我个人每天大概会打开百来次网页甚至更多,时间越长历史记录会越多多。此时使用json存储一旦数据量加大,势必会影响效率。

故需要选择一个新的存储方式。展开思考:Edge是用什么存储的呢?

二、探究Edge历史记录存储方式

经过几番查找终于找到Edge数据存储位置:C:\Users\用户\AppData\Local\Microsoft\Edge\User Data\Default

浏览一下看看是否有所需的文件,咦?发现了Bookmarks,这应该是存储收藏夹数据的吧,尝试打开看看

使用Notepad++打开看看,咦,这不巧了吗?竟然也是json存储。和之前收藏夹的存储想法不谋而合。

Edge历史记录该不会也是json存储吧? 令人担忧

继续浏览该目录,这应该就是保存历史记录的

打开看看:

心里松了一口气,还好不是Json。

那究竟是怎样存储的呢?可以看到该文件的第一行 “SQLite format”,它可能是一个SQLite数据库文件。

使用SQLiteSpy打开看看,A我去了,果然是SQLite数据库文件。

个人猜测 Downloads存储的是下载历史,keyword_search_terms是搜索历史

visit存储访问历史,也就是我们所需要的历史记录。打开visit,

虽然没直接存储url,但有url的id,打开urls表

揍是它,到此可以得出:Edge的历史记录存储在SQLite 格式的文件中。那好,我们也使用SQLite作为历史记录的存储方式。

三、数据存储设计

上面已分析出Edge的历史记录存储方式,这里照葫芦画瓢也采用SQLite存储数据。

ORM框架选型,.Net 的ORM框架有很多。如SqlSugar、Dos.ORM、Entity Framework 、NHibernate等等。

近两年 SqlSugar总体评价较好,这里采用SqlSugar,官方文档:http://donet5.com/Home/Doc

NuGet Package Manager中添加 SqlSugarCore引用:

新建HistoryModel 用户存储历史记录,目前只建一张表。后期有需要在按需扩展。

[SugarTable("history", "f10")]
public class HistoryModel
{
[SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public DateTime VisitTime { get; set; }
public int FormVisit { get; set; }
}

新建 DbContext用于配置 SqlSugarClient

public class DbContext
{
private SqlSugarClient _db;
public SqlSugarClient Db
{
get => _db;
private set => _db = value;
}
public DbContext()
{
string connStr = $"DataSource={Environment.CurrentDirectory}\\History.db";
ConnectionConfig config = new ConnectionConfig
{
ConnectionString = connStr,
DbType = DbType.Sqlite,
InitKeyType = InitKeyType.Attribute,
IsAutoCloseConnection = true,
};
_db = new SqlSugarClient(config);
}
}

新建 DbSeed用于数据库初始化

public static class DbSeed
{
private static readonly DbContext _context;
static DbSeed()
{
_context = new DbContext();
}
public static void InitData()
{
//创建数据库
_context.Db.DbMaintenance.CreateDatabase(); //创建表,反射获取指定数据表
var modelTypes = from table in Assembly.GetExecutingAssembly().GetTypes()
where table.IsClass && table.Namespace == "Cys_Model.Tables"
select table; foreach (var t in modelTypes.ToList())
{
if (_context.Db.DbMaintenance.IsAnyTable(t.Name)) continue;
_context.Db.CodeFirst.InitTables(t);
}
}
}

四、历史记录界面设计

首先看看Edge历史记录弹窗面板,如图所示:

可分为上下两部分

上半部分分为搜索,子菜单,固定到右侧(本章暂不处理)

下半部分为数据列表(本章完成这一部分)

Edge的历史记录弹窗面板的外部展示方式与收藏夹菜单类似也是弹窗,可以采用Popup实现。新建HistoryUc用户控件,代码如下:

<UserControl x:Class="MWebBrowser.View.HistoryUc"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:history="clr-namespace:MWebBrowser.View.History"
mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="40">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="ListBoxTemplate">
<history:HistoryItemUc/>
</DataTemplate>
</Grid.Resources>
<ToggleButton x:Name="HistoryButton" Style="{DynamicResource ToggleButton.FontButton}" Checked="HistoryButton_OnChecked"
Unchecked="HistoryButton_OnUnchecked" Content="" FontSize="32" Background="Transparent" IsChecked="{Binding ElementName=FavoritesPop,Path=IsOpen}"/>
<Popup x:Name="FavoritesPop" PopupAnimation="Fade" Placement="Bottom" PlacementTarget="{Binding ElementName=FavoritesButton}"
StaysOpen="False" AllowsTransparency="True" HorizontalOffset="-330">
<Border x:Name="PopBorder" Background="{DynamicResource WebBrowserBrushes.WebMenuBackground}" CornerRadius="5">
<Border.Effect>
<DropShadowEffect Color="{DynamicResource Color.MenuItemDropShadowBrush}" Opacity="0.3" ShadowDepth="3"/>
</Border.Effect>
<Grid Width="360" Height="660">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Height="40">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="历史记录" VerticalAlignment="Center" FontSize="18" Margin="10,0,0,0" Foreground="{DynamicResource WebBrowserBrushes.DefaultForeground}"/>
</Grid>
<Rectangle Grid.Row="1" Height="1" Fill="{DynamicResource WebBrowserBrushes.WebMenuDivideLine}"/>
<ListBox Grid.Row="2" x:Name="HistoryListBox" ItemsSource="{Binding HistoryList}" Background="Transparent" ItemTemplate="{StaticResource ListBoxTemplate}" Style="{DynamicResource CustomListBox.HistoryListBox}"/>
</Grid>
</Border>
</Popup>
</Grid>
</UserControl>

HistoryButton 控制Popup开闭。Popup中 添加 ListBox用于展示数据列

HistoryUc.xaml.cs代码:

using Cys_Controls.Code;
using MWebBrowser.ViewModel;
using System.Windows.Controls; namespace MWebBrowser.View
{
/// <summary>
/// Interaction logic for HistoryUc.xaml
/// </summary>
public partial class HistoryUc : UserControl
{
private readonly HistoryViewModel _viewModel;
private double _offset;
public HistoryUc()
{
InitializeComponent();
_viewModel = new HistoryViewModel();
this.DataContext = _viewModel;
HistoryListBox.DataContext = _viewModel;
}
private void ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (!(sender is ScrollViewer scrollViewer)) return;
if (_offset > scrollViewer.VerticalOffset) return;
_offset = scrollViewer.VerticalOffset;
if ((int)scrollViewer.VerticalOffset >= (scrollViewer.ScrollableHeight - 3))
{
_viewModel.GetHistoryList();
}
}
private void HistoryButton_OnChecked(object sender, System.Windows.RoutedEventArgs e)
{
_viewModel.ReSet();
_viewModel.GetHistoryList();
ScrollViewer sv = ControlHelper.FindVisualChild<ScrollViewer>(HistoryListBox);
if (sv != null)
{
sv.ScrollChanged -= ScrollChanged;
sv.ScrollChanged += ScrollChanged;
}
} private void HistoryButton_OnUnchecked(object sender, System.Windows.RoutedEventArgs e)
{ }
}
}

这里需要注意由于历史记录比较多,故需要采用分页处理,当前采用的是滚动条即将触底时获取数据,每次获取20条。

需要自定义ListBoxItem的外观,创建HistoryItemUc

<UserControl x:Class="MWebBrowser.View.History.HistoryItemUc"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="40" d:DesignWidth="400">
<Grid Height="40">
<!--<TextBlock Text="{Binding PublishTimeStr}" FontWeight="Bold" FontSize="16" Foreground="#FFFFFF" Visibility="{Binding GroupVisible}"/>-->
<Grid>
<Grid Margin="5,0">
<Border Margin="0,0,20,0" MaxWidth="350" CornerRadius="5" Background="{Binding BackColorBrush}" MouseEnter="History_OnMouseEnter" MouseLeave="History_OnMouseLeave" MouseLeftButtonDown="History_OnMouseLeftButtonDown" Cursor="Hand">
<Grid Margin="10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Width="16" Height="16" Grid.Column="0" Source="{Binding Favicon}"/>
<TextBlock Margin="10,0,0,0" Grid.Column="1" FontSize="14" TextTrimming="CharacterEllipsis" Foreground="#FFFFFF" Text="{Binding Title}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock TextTrimming="CharacterEllipsis" Margin="10,0,0,0" Visibility="{Binding DateVisible}" Grid.Column="2" Text="{Binding VisitTimeStr}" VerticalAlignment="Center" Foreground="{DynamicResource WebBrowserBrushes.HistoryDateForeground}"/>
<Button Visibility="{Binding CloseVisible}" Grid.Column="2" Margin="10,0,0,0" Style="{DynamicResource Button.DownloadCloseButton}" Click="Delete_OnClick" VerticalAlignment="Center"/>
</Grid>
</Border>
</Grid>
</Grid>
</Grid>
</UserControl>

HistoryItemUc.xaml.cs代码如下:

using Cys_Controls.Code;
using MWebBrowser.ViewModel;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media; namespace MWebBrowser.View.History
{
/// <summary>
/// Interaction logic for HistoryItemUc.xaml
/// </summary>
public partial class HistoryItemUc : UserControl
{
public HistoryItemUc()
{
InitializeComponent();
} private void History_OnMouseEnter(object sender, MouseEventArgs e)
{
if (!(this.DataContext is HistoryItemViewModel viewModel)) return; viewModel.BackColorBrush = Application.Current.MainWindow?.FindResource("WebBrowserBrushes.HistoryBackgroundOver") as SolidColorBrush;
viewModel.DateVisible = Visibility.Collapsed;
viewModel.CloseVisible = Visibility.Visible;
} private void History_OnMouseLeave(object sender, MouseEventArgs e)
{
if (!(this.DataContext is HistoryItemViewModel viewModel)) return; viewModel.BackColorBrush = Application.Current.MainWindow?.FindResource("WebBrowserBrushes.HistoryBackground") as SolidColorBrush;
viewModel.DateVisible = Visibility.Visible;
viewModel.CloseVisible = Visibility.Collapsed;
} private void History_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!(this.DataContext is HistoryItemViewModel viewModel)) return;
try
{
var uc = ControlHelper.FindVisualChild<WebTabControlUc>(Application.Current.MainWindow);
uc.TabItemAdd(viewModel.Url);
}
catch (Exception ex)
{ }
} private void Delete_OnClick(object sender, RoutedEventArgs e)
{
if (!(this.DataContext is HistoryItemViewModel viewModel)) return;
var uc = ControlHelper.FindVisualChild<WebTabControlUc>(Application.Current.MainWindow);
var historyUc = ControlHelper.FindVisualChild<HistoryUc>(uc);
if (historyUc?.DataContext is HistoryViewModel hvm)
{
hvm.DeleteHistoryItem(viewModel);
}
}
}
}

五、运行效果

五、源码地址

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

项目邀请:如对该项目有兴趣,欢迎联系我共同开发!!!

基于CefSharp开发浏览器(九)浏览器历史记录弹窗面板的更多相关文章

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

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

  2. 基于.net开发chrome核心浏览器

    本文转载自:http://www.cnblogs.com/liulun/archive/2013/04/20/3031502.html 一: 上一篇的链接: 基于.net开发chrome核心浏览器[一 ...

  3. 基于.net开发chrome核心浏览器【二】

    原文:基于.net开发chrome核心浏览器[二] 一: 上一篇的链接: 基于.net开发chrome核心浏览器[一] 二: 相关资源介绍: chrome Frame: 让IE有一颗chrome的心, ...

  4. 基于.net开发chrome核心浏览器【七】

    这是一个系列的文章,前面六篇文章的地址如下: 基于.net开发chrome核心浏览器[六] 基于.net开发chrome核心浏览器[五] 基于.net开发chrome核心浏览器[四] 基于.net开发 ...

  5. 基于.net开发chrome核心浏览器【四】

    原文:基于.net开发chrome核心浏览器[四] 一: 上周去北京出差,给国家电网的项目做架构方案,每天都很晚睡,客户那边的副总也这样拼命工作. 累的不行了,直接导致第四篇文章没有按时发出来. 希望 ...

  6. 基于.net开发chrome核心浏览器【三】

    原文:基于.net开发chrome核心浏览器[三] 本篇我们讲解怎么用CefGlue开发一个最简单的浏览器 一: CefGlue是建立在Cef项目之上的,Cef项目是C/C++的项目:CefGlue只 ...

  7. 基于.net开发chrome核心浏览器【一】

    原文:基于.net开发chrome核心浏览器[一] 说明: 这是本系列的第一篇文章,我会尽快发后续的文章. 源起 1.加快葬送IE6浏览器的进程 世界上使用IE6浏览器最多的地方在中国 中国使用IE6 ...

  8. 基于.net开发chrome核心浏览器【五】

    一:本篇将解决的问题 本章主要为了解决一下几个问题: 1.JsDialog的按钮错位的问题 我们开发出的浏览器,在有些操系统上调用alert,confirm之类的对话框时,确定和取消按钮会出现错位的情 ...

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

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

随机推荐

  1. JVM你了解?

    1.谈谈你对JAVA的理解 平台无关性(一次编译,到处运行) GC(不必手动释放堆内存) 语言特性(泛型.lambda) 面向对象(继承,封装,多态) 类库 异常处理 2.平台无关性怎么实现

  2. CF1474-B. Different Divisors

    CF1474-B. Different Divisors 题意: 题目给出你一个\(d\),要求你找出一个数字\(y\),找到的\(y\)至少有四个整数因子并且任意两个因子之间的差至少为\(d\). ...

  3. [Golang]-5 协程、通道及其缓冲、同步、方向和选择器

    目录 协程 通道 通道缓冲 通道同步 通道方向 通道选择器 协程 Go 协程 在执行上来说是轻量级的线程. 代码演示 import ( "fmt" "time" ...

  4. kubernetes实战-交付dubbo服务到k8s集群(六)使用blue ocean流水线构建dubbo-consumer服务

    我们这里的dubbo-consumer是dubbo-demo-service的消费者: 我们之前已经在jenkins配置好了流水线,只需要填写参数就行了. 由于dubbo-consumer用的gite ...

  5. 2.了解nginx常用的配置

    作者 微信:tangy8080 电子邮箱:914661180@qq.com 更新时间:2019-07-10 20:56:10 星期三 欢迎您订阅和分享我的订阅号,订阅号内会不定期分享一些我自己学习过程 ...

  6. 苹果证书p12和描述文件的创建方法

    在2020年之前,我们在使用香蕉云编创建苹果证书的时候,只需要注册苹果开发者账号,但不需要缴费成为开发者. 在2020年之后,需要先缴费成为苹果开发者. 假如你还没有注册苹果开发者账号,可以先参考下下 ...

  7. Spring-cloud-netflix-hystrix

    服务注册中心eureka-server已经搭好,并且SPRING-CLOUD-NETFLIX-EUREKA-CLIENT-APPLICATION提供一个hello服务 畏怯还编写一个eureka-cl ...

  8. POJ 2288 Islands and Bridges(状压DP)题解

    题意:n个点,m有向边,w[i]表示i的价值,求价值最大的哈密顿图(只经过所有点一次).价值为:所有点的w之和,加上,每条边的价值 = w[i] * w[j],加上,如果连续的三个点相互连接的价值 = ...

  9. Gym 101170F Free Weights(二分)题解

    题意:给出两行,每一行都有n个数组,一共有2 * n个,大小为1~n,每个有两个.现在可以进行操作:拿出一个物品i,然后放到一个空格,花费i.可以任意平移物品,平移没有花费.每一行空间无限.要求你把一 ...

  10. Springboot如何启用文件上传功能

    网上的文章在写 "springboot文件上传" 时,都让你加上模版引擎,我只想说,我用不上,加模版引擎,你是觉得我脑子坏了,还是觉得我拿不动刀了. springboot如何启用文 ...