一、前言

前两篇文章写的是关于浏览器收藏夹的内容,因为收藏夹的内容不会太多,故采用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. codeforces 1019B The hat 【交互题+二分搜索】

    题目链接:戳这里 学习题解:戳这里

  2. URAL 1132 Square Root(二次剩余定理)题解

    题意: 求\(x^2 \equiv a \mod p\) 的所有整数解 思路: 二次剩余定理求解. 参考: 二次剩余Cipolla's algorithm学习笔记 板子: //二次剩余,p是奇质数 l ...

  3. DC1(msf drupal7+suid-find提权)

    这边我们靶机是仅主机模式,IP是192.168.56.101,,直接上msf拿到shell,  不过payload要改一下 改成php/meterperter/bind_tcp 拿到shell了 ,采 ...

  4. CNN可视化技术总结(三)--类可视化

    CNN可视化技术总结(一)-特征图可视化 CNN可视化技术总结(二)--卷积核可视化 导言: 前面我们介绍了两种可视化方法,特征图可视化和卷积核可视化,这两种方法在论文中都比较常见,这两种更多的是用于 ...

  5. How to enable HTTPS for local development in macOS using Chrome

    How to enable HTTPS for local development in macOS using Chrome HTTPS, macOS, Chrome local HTTPS htt ...

  6. PM2 All In One

    PM2 All In One https://pm2.keymetrics.io/ https://pm2.io/ $ yarn global add pm2 # OR $ npm install p ...

  7. github & personal access token

    github & personal access token OAuth https://github.com/xgqfrms/webtrc-in-action/issues/1#issuec ...

  8. Web Components & HTML5 & template & slot

    Web Components & HTML5 & template & slot https://developer.mozilla.org/en-US/docs/Web/HT ...

  9. input support upload excel only

    input support upload excel only demo https://codepen.io/xgqfrms/pen/vYONpLB <!-- <input placeh ...

  10. Flutter中mixin的使用

    页表页面 这是一个普通的展示数据,上拉加载更多数据的列表. 其中有一个类型为List<T>的数据列表listData,有个page数据用于分页,isLoading用来判断是否正在加载数据, ...