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

一、前言

上一篇文章 基于CefSharp开发(七)浏览器收藏夹菜单 简单实现了部分收藏夹功能 如(添加文件夹、添加收藏、删除、右键菜单部分功能)

后续代码中对MTreeViewItem进行了扩展,增加了TextBox用于编辑Item及相应的依赖属性,实现了重命名操作。

浏览器除了有收藏夹菜单,还需要有收藏夹栏用于快捷访问,本章将开发简易的收藏夹栏。

二、收藏夹栏分析

如下面两幅图所示,前者为收藏夹菜单样式,后者为收藏夹栏样式,两者数据结构相同,只是展示形式略有差异。故可采用同一数据结构

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

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

观其展示形式与MMenu接近,故此处将采用Menu进行样式扩展开发。

收藏夹栏支持右键功能,故需要添加ContextMenu支持。

收藏夹栏与收藏夹菜单展示的同一数据,属于同一功能,故需增加联动。

下面将逐步完成以上内容的开发,由于样式及结构均与收藏夹菜单接近,故本章不对样式进行叙述,直撸代码

三、创建自定义控件并添加至WebTabControlUc

1、新增定义控件MFavorites、MFavoritesItem

样式可复制MMenu、MMenuItem

MFavorites.xaml

基于CefSharp开发浏览器(八)浏览器收藏夹栏基于CefSharp开发浏览器(八)浏览器收藏夹栏
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Cys_CustomControls.Controls">
<Style TargetType="{x:Type local:MFavorites}">
<Setter Property="Foreground" Value="{DynamicResource ColorBrush.FontDefaultColor}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Width" Value="Auto"/>
<Setter Property="Height" Value="35"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MFavorites}">
<Border Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

MFavorites.xaml.cs

基于CefSharp开发浏览器(八)浏览器收藏夹栏基于CefSharp开发浏览器(八)浏览器收藏夹栏
public class MFavorites : Menu
{
static MFavorites()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MFavorites), new FrameworkPropertyMetadata(typeof(MFavorites)));
}
}

MFavoritesItem.xaml

基于CefSharp开发浏览器(八)浏览器收藏夹栏基于CefSharp开发浏览器(八)浏览器收藏夹栏
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Cys_CustomControls.Controls"> <ControlTemplate x:Key="MTopLevelHeaderTemplate" TargetType="{x:Type local:MFavoritesItem}">
<Border x:Name="templateRoot" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{TemplateBinding CornerRadius}" SnapsToDevicePixels="true">
<Grid>
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="PART_TextGrid" Opacity="0.8" Margin="10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="Icon" FontSize="20" HorizontalAlignment="Center" Text="{TemplateBinding Icon}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" Foreground="{TemplateBinding IconForeground}"/>
<ContentPresenter Margin="10,0,0,0" Grid.Column="1" ContentSource="Header" x:Name="PART_Header" HorizontalAlignment="Center" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
</Grid>
<Popup x:Name="PART_Popup" AllowsTransparency="true" Focusable="false" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}"
Placement="Bottom" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" PlacementTarget="{Binding ElementName=templateRoot}" Width="{TemplateBinding PopupWidth}">
<Border x:Name="SubMenuBorder" Margin="0 0 5 5" >
<Border.Effect>
<DropShadowEffect Color="{DynamicResource Color.MenuItemDropShadowBrush}" Opacity="0.3" ShadowDepth="3"/>
</Border.Effect>
<Border Background="{DynamicResource WebBrowserBrushes.WebMenuBackground}" BorderThickness="1" CornerRadius="5">
<ScrollViewer x:Name="SubMenuScrollViewer" Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}" Margin="0,5">
<Grid RenderOptions.ClearTypeHint="Enabled" Background="Transparent">
<Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=SubMenuBorder}"
Height="{Binding ActualHeight, ElementName=SubMenuBorder}"
Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/>
</Canvas>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle"
Grid.IsSharedSizeScope="true" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
</Grid>
</ScrollViewer>
</Border>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSuspendingPopupAnimation" Value="true">
<Setter Property="PopupAnimation" TargetName="PART_Popup" Value="None"/>
</Trigger>
<!--<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>-->
<Trigger Property="ScrollViewer.CanContentScroll" SourceName="SubMenuScrollViewer" Value="false">
<Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=SubMenuScrollViewer}"/>
<Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=SubMenuScrollViewer}"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="templateRoot" Property="Background" Value="{DynamicResource WebBrowserBrushes.WebMenuIsMouseOverBackground}"/>
<Setter TargetName="PART_TextGrid" Property="Opacity" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate> <ControlTemplate x:Key="MTopLevelItemTemplate" TargetType="{x:Type local:MFavoritesItem}">
<Border x:Name="templateRoot" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{TemplateBinding CornerRadius}" SnapsToDevicePixels="true">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="PART_TextGrid" Opacity="0.8" Margin="10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="Icon" FontSize="20" HorizontalAlignment="Center" Text="{TemplateBinding Icon}" Foreground="{TemplateBinding IconForeground}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
<ContentPresenter Margin="10,0,0,0" ContentSource="Header" HorizontalAlignment="Center" Grid.Column="1" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!--<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>-->
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="templateRoot" Property="Background" Value="{DynamicResource WebBrowserBrushes.WebMenuIsMouseOverBackground}"/>
<Setter TargetName="PART_TextGrid" Property="Opacity" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate> <ControlTemplate x:Key="MSubmenuHeaderTemplate" TargetType="{x:Type local:MFavoritesItem}">
<Border x:Name="templateRoot" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Height="35" SnapsToDevicePixels="true">
<Grid >
<Grid HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" x:Name="Icon" Width="20" FontSize="20" HorizontalAlignment="Center" Text="{TemplateBinding Icon}" Foreground="{TemplateBinding IconForeground}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
<ContentPresenter Margin="10,0,0,0" Grid.Column="1" ContentSource="Header" HorizontalAlignment="Center" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
</Grid>
<Path x:Name="RightArrow" Data="M 0,0 L 7,7 L 0,14 Z"
Fill="{TemplateBinding Foreground}"
HorizontalAlignment="Right" Margin="0,0,5,0" VerticalAlignment="Center" Opacity="0.6"/> <Popup x:Name="PART_Popup" AllowsTransparency="true" Focusable="false" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}"
Placement="Right" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" PlacementTarget="{Binding ElementName=templateRoot}" VerticalOffset="-5" Width="{TemplateBinding PopupWidth}">
<Border x:Name="SubMenuBorder" Margin="0 0 5 5" >
<Border.Effect>
<DropShadowEffect Color="{DynamicResource Color.MenuItemDropShadowBrush}" Opacity="0.3" ShadowDepth="3"/>
</Border.Effect>
<Border Background="{DynamicResource WebBrowserBrushes.WebMenuBackground}" BorderThickness="1" CornerRadius="5">
<ScrollViewer x:Name="SubMenuScrollViewer" Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}" Margin="0,5">
<Grid RenderOptions.ClearTypeHint="Enabled" Background="Transparent">
<Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=SubMenuBorder}"
Height="{Binding ActualHeight, ElementName=SubMenuBorder}"
Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/>
</Canvas>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle"
Grid.IsSharedSizeScope="true" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
</Grid>
</ScrollViewer>
</Border>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSuspendingPopupAnimation" Value="true">
<Setter Property="PopupAnimation" TargetName="PART_Popup" Value="None"/>
</Trigger>
<!--<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>-->
<Trigger Property="IsChecked" Value="True">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="ScrollViewer.CanContentScroll" SourceName="SubMenuScrollViewer" Value="false">
<Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=SubMenuScrollViewer}"/>
<Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=SubMenuScrollViewer}"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="templateRoot" Property="Background" Value="{DynamicResource WebBrowserBrushes.WebMenuIsMouseOverBackground}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate> <ControlTemplate x:Key="MSubmenuItemTemplate" TargetType="{x:Type local:MFavoritesItem}">
<Border x:Name="templateRoot" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Height="35" SnapsToDevicePixels="true">
<Grid HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" x:Name="Icon" Width="20" FontSize="20" HorizontalAlignment="Center" Text="{TemplateBinding Icon}" Foreground="{TemplateBinding IconForeground}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
<ContentPresenter Margin="10,0,0,0" Grid.Column="1" x:Name="menuHeaderContainer" HorizontalAlignment="Center" ContentSource="Header" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!--<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>-->
<Trigger Property="IsChecked" Value="True">
<Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="templateRoot" Property="Background" Value="{DynamicResource WebBrowserBrushes.WebMenuIsMouseOverBackground}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate> <Style TargetType="{x:Type local:MFavoritesItem}">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="CornerRadius" Value="5"/>
<Setter Property="Background" Value="{DynamicResource WebBrowserBrushes.TabHeaderIsSelectedBackground}"/>
<Setter Property="Foreground" Value="{DynamicResource ColorBrush.FontPrimaryColor}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="FontFamily" Value="Microsoft YaHei"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Height" Value="35"/>
<Setter Property="Width" Value="Auto"/>
<Setter Property="MinWidth" Value="40"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template" Value="{StaticResource MSubmenuItemTemplate}"/>
<Style.Triggers>
<Trigger Property="Role" Value="TopLevelHeader">
<Setter Property="BorderThickness" Value="0,0,1,0"/>
<Setter Property="PopupWidth" Value="300"/>
<Setter Property="Template" Value="{StaticResource MTopLevelHeaderTemplate}"/>
</Trigger>
<Trigger Property="Role" Value="TopLevelItem">
<Setter Property="BorderThickness" Value="0,0,1,0"/>
<Setter Property="Template" Value="{StaticResource MTopLevelItemTemplate}"/>
</Trigger>
<Trigger Property="Role" Value="SubmenuHeader">
<Setter Property="PopupWidth" Value="300"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{DynamicResource ColorBrush.FontPrimaryColor}"/>
<Setter Property="Template" Value="{StaticResource MSubmenuHeaderTemplate}"/>
<Setter Property="Padding" Value="3,0,0,0"/>
</Trigger>
<Trigger Property="Role" Value="SubmenuItem">
<Setter Property="Foreground" Value="{DynamicResource ColorBrush.FontPrimaryColor}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template" Value="{StaticResource MSubmenuItemTemplate}"/>
<Setter Property="Padding" Value="3,0,0,0"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>

MFavoritesItem.xaml.cs

基于CefSharp开发浏览器(八)浏览器收藏夹栏基于CefSharp开发浏览器(八)浏览器收藏夹栏
public class MFavoritesItem : MenuItem
{
static MFavoritesItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MFavoritesItem), new FrameworkPropertyMetadata(typeof(MFavoritesItem)));
} #region == DependencyProperty==
#region == CornerRadius==
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(MFavoritesItem),
new PropertyMetadata(null)); /// <summary>
/// CornerRadius
/// </summary>
public CornerRadius CornerRadius
{
get => (CornerRadius)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
#endregion #region == PopupWidth==
public static readonly DependencyProperty PopupWidthProperty = DependencyProperty.Register("PopupWidth", typeof(double), typeof(MFavoritesItem),
new PropertyMetadata(null)); /// <summary>
/// PopupWidth
/// </summary>
public double PopupWidth
{
get => (double)GetValue(PopupWidthProperty);
set => SetValue(PopupWidthProperty, value);
}
#endregion /// <summary>
/// IconForeground 字体图标前景色
/// </summary>
public static readonly DependencyProperty IconForegroundProperty = DependencyProperty.Register("IconForeground", typeof(Brush), typeof(MFavoritesItem));
public Brush IconForeground
{
get => (Brush)GetValue(IconForegroundProperty);
set => SetValue(IconForegroundProperty, value);
} /// <summary>
/// ItemMargin
/// </summary>
public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register("ItemMargin", typeof(Thickness), typeof(MFavoritesItem));
public Thickness ItemMargin
{
get => (Thickness)GetValue(ItemMarginProperty);
set => SetValue(ItemMarginProperty, value);
} /// <summary>
/// TextMaxWidth
/// </summary>
public static readonly DependencyProperty TextMaxWidthProperty = DependencyProperty.Register("TextMaxWidth", typeof(double), typeof(MFavoritesItem));
public double TextMaxWidth
{
get => (double)GetValue(TextMaxWidthProperty);
set => SetValue(TextMaxWidthProperty, value);
}
#endregion public int Type { get; set; } public int Level { get; set; }
public int NodeId { get; set; }
}

2、接着新增用户控件FavoritesBarUc

用于承接MFavorites代码如下:

FavoritesBarUc.xaml

基于CefSharp开发浏览器(八)浏览器收藏夹栏基于CefSharp开发浏览器(八)浏览器收藏夹栏
<UserControl x:Class="MWebBrowser.View.FavoritesBarUc"
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:controls="clr-namespace:Cys_CustomControls.Controls;assembly=Cys_CustomControls"
mc:Ignorable="d"
d:DesignHeight="40" d:DesignWidth="800" Height="40" Background="{DynamicResource WebBrowserBrushes.TabHeaderIsSelectedBackground}">
<Grid VerticalAlignment="Center">
<controls:MFavorites x:Name="MenuParent" ContextMenuOpening="FavoritesTree_OnContextMenuOpening" ScrollViewer.HorizontalScrollBarVisibility="Hidden" PreviewMouseLeftButtonUp="FavoritesTree_OnPreviewMouseLeftButtonUp">
<controls:MFavorites.ContextMenu>
<ContextMenu x:Name="FavoritesContextMenu" Style="{DynamicResource WebCustomMenus.DefaultContextMenu}">
<controls:MMenuItem Tag="0" x:Name="OpenAllFolder" Header="全部打开(16个)" Icon=""/>
<controls:MMenuItem Tag="1" x:Name="OpenNewAllFolder" Header="在新建窗口中全部打开(16个)" Icon=""/>
<controls:MMenuItem Tag="2" Header="在新 InPrivate窗口全部打开(16个)" Icon=""/>
<controls:MMenuItem Tag="4" Header="按名称排序" Icon=""/>
<controls:MMenuItem Tag="5" x:Name="ReName" Header="重命名" Icon="" Click="ReName_OnClick"/>
<controls:MMenuItem Tag="6" x:Name="DeleteNode" Header="删除" Icon="" IconFontSize="26" Click="Delete_OnClick"/>
<controls:MMenuItem Tag="7" Header="将当前标签页添加到文件夹" Icon="" Click="AddFavorites_OnClick"/>
<controls:MMenuItem Tag="8" Header="将所有标签页添加到文件夹" Visibility="Collapsed"/>
<controls:MMenuItem Tag="9" Header="添加文件夹" Icon="" Click="AddFolder_OnClick"/>
</ContextMenu>
</controls:MFavorites.ContextMenu>
</controls:MFavorites>
<Popup x:Name="ReNamePop" PopupAnimation="Fade" Placement="Bottom" PlacementTarget="{Binding ElementName=MenuParent}"
StaysOpen="False" AllowsTransparency="True" VerticalOffset="-40">
<Border Background="{DynamicResource WebBrowserBrushes.WebMenuBackground}" CornerRadius="5">
<Border.Effect>
<DropShadowEffect Color="{DynamicResource Color.MenuItemDropShadowBrush}" Opacity="0.3" ShadowDepth="3"/>
</Border.Effect>
<Grid Width="320" Height="140">
<Grid Margin="20,20,20,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="编辑文件夹名称" FontSize="18" Foreground="{DynamicResource ColorBrush.FontPrimaryColor}"/>
<StackPanel Grid.Row="1" Margin="0,10,0,0" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="名称" Foreground="{DynamicResource ColorBrush.FontPrimaryColor}" VerticalAlignment="Center"/>
<TextBox x:Name="FolderName" Height="30" Width="236" Margin="10,0,0,0" Style="{DynamicResource TextBox.ReName}" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Grid.Row="2" Margin="0,15,0,0" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="保存" Style="{DynamicResource Button.ReSave}" Click="ReSave_OnClick"/>
<Button Content="取消" Style="{DynamicResource Button.ReCancel}" Click="ReCancel_OnClick" Margin="10,0,0,0"/>
</StackPanel>
</Grid>
</Grid>
</Border>
</Popup>
</Grid>
</UserControl>

FavoritesBarUc.xaml.cs

基于CefSharp开发浏览器(八)浏览器收藏夹栏基于CefSharp开发浏览器(八)浏览器收藏夹栏
using Cys_Common;
using Cys_Controls.Code;
using Cys_CustomControls.Controls;
using Cys_Model;
using MWebBrowser.Code.Helpers;
using MWebBrowser.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media; namespace MWebBrowser.View
{
/// <summary>
/// Interaction logic for FavoritesBarUc.xaml
/// </summary>
public partial class FavoritesBarUc : UserControl
{
private readonly double _textMaxWidth = 300;
/// <summary>
/// 记录当前右键选中的Item;
/// </summary>
private MFavoritesItem _currentRightItem;
public Func<WebTabControlViewModel> GetWebUrlEvent;
public Action<string> OpenNewTabEvent;
public FavoritesBarUc()
{
InitializeComponent();
this.Loaded += FavoritesBarUc_Loaded;
} private void FavoritesBarUc_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
if (this.IsInDesignMode()) return;
GetFavoritesInfo();
} private void GetFavoritesInfo()
{
List<TreeNode> root = GetNodes(-1, GlobalInfo.FavoritesSetting.FavoritesInfos);
if (root == null || root.Count <= 0 || root[0].ChildNodes.Count <= 0) return;
foreach (var child in root[0].ChildNodes)
{
AddFavoritesItem(null, child, true);
}
} private List<TreeNode> GetNodes(int parentId, List<TreeNode> nodes)
{
List<TreeNode> mainNodes = nodes.Where(x => x.ParentId == parentId).OrderByDescending(x => x.Type).ToList();
List<TreeNode> otherNodes = nodes.Where(x => x.ParentId != parentId).OrderByDescending(x => x.Type).ToList();
foreach (TreeNode node in mainNodes)
node.ChildNodes = GetNodes(node.NodeId, otherNodes);
return mainNodes;
} /// <summary>
/// 递归添加子集
/// </summary>
/// <param name="parent"></param>
/// <param name="treeNode"></param>
/// <param name="isRoot"></param>
private void AddFavoritesItem(MFavoritesItem parent, TreeNode treeNode, bool isRoot)
{
var item = GetNewFavoritesItem(treeNode);
if (treeNode.ChildNodes.Count > 0)
{
foreach (var child in treeNode.ChildNodes)
{
AddFavoritesItem(item, child, false);
}
} if (!isRoot)
parent.Items.Add(item);
else
MenuParent.Items.Add(item);
} /// <summary>
/// 获取FavoritesItem
/// </summary>
/// <param name="treeNode"></param>
/// <returns></returns>
private MFavoritesItem GetNewFavoritesItem(TreeNode treeNode)
{
return new MFavoritesItem
{
Header = treeNode.NodeName,
Type = treeNode.Type,
NodeId = treeNode.NodeId,
Level = treeNode.Level,
TextMaxWidth = _textMaxWidth,
Icon = treeNode.Type == 0 ? "\ueb1e" : "\ue903",
IconForeground = treeNode.Type == 0 ? new SolidColorBrush(Color.FromRgb(255, 255, 255)) : new SolidColorBrush(Color.FromRgb(255, 205, 44)),
};
} /// <summary>
/// 处理右键菜单打开前的行为
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FavoritesTree_OnContextMenuOpening(object sender, ContextMenuEventArgs e)
{
_currentRightItem = ControlHelper.FindVisualParent<MFavoritesItem>(e.OriginalSource as DependencyObject);
if (null == _currentRightItem)
{
e.Handled = true;
return;
}
if (_currentRightItem.Type == 0)
{
OpenAllFolder.Visibility = Visibility.Collapsed;
OpenNewAllFolder.Visibility = Visibility.Collapsed;
ReName.Visibility = Visibility.Collapsed;
}
else
{
OpenAllFolder.Visibility = Visibility.Visible;
OpenNewAllFolder.Visibility = Visibility.Visible;
ReName.Visibility = Visibility.Visible;
}
} private void FavoritesTree_OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var item = ControlHelper.FindVisualParent<MFavoritesItem>(e.OriginalSource as DependencyObject);
if (item.Type == 1) return;
if (!GlobalInfo.FavoritesSetting.FavoritesInfos.Exists(x => x.NodeId == item.NodeId)) return;
var treeNode = GlobalInfo.FavoritesSetting.FavoritesInfos.First(x => x.NodeId == item.NodeId);
OpenNewTabEvent?.Invoke(treeNode.Url);
} /// <summary>
/// 添加收藏
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddFavorites_OnClick(object sender, RoutedEventArgs e)
{
var model = GetWebUrlEvent?.Invoke();
if (null == model) return;
if (_currentRightItem?.Type != 1) return;
var newTreeNode = GetNewTreeNodeInfo(false, 0, model.Title, model.CurrentUrl);
_currentRightItem.Items.Add(newTreeNode.Item2);
GlobalInfo.FavoritesSetting.FavoritesInfos.Add(newTreeNode.Item1);
}
/// <summary>
/// 添加文件夹
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AddFolder_OnClick(object sender, RoutedEventArgs e)
{
var newTreeNode = GetNewTreeNodeInfo(false, 1, "新建文件夹", null);
if (_currentRightItem != null && _currentRightItem.Type == 1)
{
_currentRightItem.Items.Add(newTreeNode.Item2);
GlobalInfo.FavoritesSetting.FavoritesInfos.Add(newTreeNode.Item1);
}
} private Tuple<TreeNode, MFavoritesItem> GetNewTreeNodeInfo(bool isRoot, int type, string nodeName, string url)
{
int parentId = 0;
int level = 1;
if (!isRoot)
{
parentId = _currentRightItem.NodeId;
level = parentId == -1 ? +1 : _currentRightItem.Level + 1;
}
int nodeMax = GlobalInfo.FavoritesSetting.FavoritesInfos.Max(x => x.NodeId);
var treeNode = new TreeNode
{
Url = url,
ParentId = parentId,
NodeId = nodeMax + 1,
NodeName = nodeName,
Type = type,
Level = level,
};
var favoritesItem = GetNewFavoritesItem(treeNode);
return new Tuple<TreeNode, MFavoritesItem>(treeNode, favoritesItem);
} #region 右键菜单操作 /// <summary>
/// 删除当前节点
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Delete_OnClick(object sender, RoutedEventArgs e)
{
if (_currentRightItem?.Parent == null) return;
for (int i = _currentRightItem.Items.Count; i > 0; i--)
{
_currentRightItem.Items.Remove(_currentRightItem.Items[^1]);
if (!GlobalInfo.FavoritesSetting.FavoritesInfos.Exists(x => x.NodeId == _currentRightItem.NodeId))
continue;
} if (_currentRightItem.Parent is MFavoritesItem items)
{
if (GlobalInfo.FavoritesSetting.FavoritesInfos.Exists(x => x.NodeId == _currentRightItem.NodeId))
{
var currentNode = (GlobalInfo.FavoritesSetting.FavoritesInfos.FirstOrDefault(x => x.NodeId == _currentRightItem.NodeId));
GlobalInfo.FavoritesSetting.FavoritesInfos.Remove(currentNode);
}
items.Items.Remove(_currentRightItem);
} if (_currentRightItem.Parent is MFavorites parent)
{
if (GlobalInfo.FavoritesSetting.FavoritesInfos.Exists(x => x.NodeId == _currentRightItem.NodeId))
{
var currentNode = (GlobalInfo.FavoritesSetting.FavoritesInfos.FirstOrDefault(x => x.NodeId == _currentRightItem.NodeId));
GlobalInfo.FavoritesSetting.FavoritesInfos.Remove(currentNode);
}
parent.Items.Remove(_currentRightItem);
}
} #region 重命名 private void ReName_OnClick(object sender, RoutedEventArgs e)
{
if (null == _currentRightItem) return;
if (_currentRightItem.Type == 0) return; ReNamePop.HorizontalOffset = (this.ActualWidth - 320) / 2;
ReNamePop.IsOpen = true;
} private void ReCancel_OnClick(object sender, RoutedEventArgs e)
{
ReNamePop.IsOpen = false;
} private void ReSave_OnClick(object sender, RoutedEventArgs e)
{
ReNamePop.IsOpen = false;
_currentRightItem.Header = FolderName.Text;
if (!GlobalInfo.FavoritesSetting.FavoritesInfos.Exists(x => x.NodeId == _currentRightItem.NodeId)) return;
var treeNode = GlobalInfo.FavoritesSetting.FavoritesInfos.First(x => x.NodeId == _currentRightItem.NodeId);
treeNode.NodeName = FolderName.Text;
} #endregion #endregion
}
}

该类中的方法用于初始化MFavorites数据

3、更改WebTabControlUc布局

新增一行用于展示FavoritesBarUc

<webBrowser:FavoritesBarUc Grid.Row="2"/>

四、运行效果

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

五、源码地址

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

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

上一篇:Linux kernel 使用 kprobe


下一篇:FPGA开发随笔汇总