基於CefSharp開發瀏覽器(九)瀏覽器歷史記錄彈窗面板
一、前言
前兩篇文章寫的是關於瀏覽器收藏夾的內容,因為收藏夾的內容不會太多,故採用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>View Code
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) { } } }View Code
這裡需要注意由於歷史記錄比較多,故需要採用分頁處理,當前採用的是滾動條即將觸底時獲取資料,每次獲取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>View Code
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); } } } }View Code
五、執行效果
五、原始碼地址
gitee地址:https://gitee.com/sirius_machao/mweb-browser
專案邀請:如對該專案有興趣,歡迎聯絡我共同開發!