基于CefSharp开发浏览器(八)浏览器收藏夹栏
一、前言
上一篇文章 基于CefSharp开发(七)浏览器收藏夹菜单 简单实现了部分收藏夹功能 如(添加文件夹、添加收藏、删除、右键菜单部分功能)
后续代码中对MTreeViewItem进行了扩展,增加了TextBox用于编辑Item及相应的依赖属性,实现了重命名操作。
浏览器除了有收藏夹菜单,还需要有收藏夹栏用于快捷访问,本章将开发简易的收藏夹栏。
二、收藏夹栏分析
如下面两幅图所示,前者为收藏夹菜单样式,后者为收藏夹栏样式,两者数据结构相同,只是展示形式略有差异。故可采用同一数据结构
观其展示形式与MMenu接近,故此处将采用Menu进行样式扩展开发。
收藏夹栏支持右键功能,故需要添加ContextMenu支持。
收藏夹栏与收藏夹菜单展示的同一数据,属于同一功能,故需增加联动。
下面将逐步完成以上内容的开发,由于样式及结构均与收藏夹菜单接近,故本章不对样式进行叙述,直撸代码
三、创建自定义控件并添加至WebTabControlUc
1、新增定义控件MFavorites、MFavoritesItem
样式可复制MMenu、MMenuItem
MFavorites.xaml
<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
public class MFavorites : Menu { static MFavorites() { DefaultStyleKeyProperty.OverrideMetadata(typeof(MFavorites), new FrameworkPropertyMetadata(typeof(MFavorites))); } }
MFavoritesItem.xaml
<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
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
<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
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"/>
四、运行效果
五、源码地址
gitee地址:https://gitee.com/sirius_machao/mweb-browser
github地址:https://github.com/sirius-chao/MWebBrowser
项目邀请:如对该项目有兴趣,欢迎联系我共同开发!!!