• 基于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>
    View Code

    MFavorites.xaml.cs

    public class MFavorites : Menu
    {
        static MFavorites()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MFavorites), new FrameworkPropertyMetadata(typeof(MFavorites)));
        }
    }
    View Code

    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>
    View Code

    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; }
    }
    View Code

    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="&#xe600;"/>
                        <controls:MMenuItem Tag="1" x:Name="OpenNewAllFolder" Header="在新建窗口中全部打开(16个)" Icon="&#xe602;"/>
                        <controls:MMenuItem Tag="2" Header="在新 InPrivate窗口全部打开(16个)" Icon="&#xe68c;"/>
                        <controls:MMenuItem Tag="4" Header="按名称排序" Icon="&#xe606;"/>
                        <controls:MMenuItem Tag="5" x:Name="ReName" Header="重命名" Icon="&#xe712;" Click="ReName_OnClick"/>
                        <controls:MMenuItem Tag="6" x:Name="DeleteNode" Header="删除" Icon="&#xe74e;" IconFontSize="26" Click="Delete_OnClick"/>
                        <controls:MMenuItem Tag="7" Header="将当前标签页添加到文件夹" Icon="&#xe659;" Click="AddFavorites_OnClick"/>
                        <controls:MMenuItem Tag="8" Header="将所有标签页添加到文件夹" Visibility="Collapsed"/>
                        <controls:MMenuItem Tag="9" Header="添加文件夹" Icon="&#xe652;" 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>
    View Code

    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
        }
    }
    View Code

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

    3、更改WebTabControlUc布局

    新增一行用于展示FavoritesBarUc

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

    四、运行效果

    五、源码地址

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

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

    天行健,君子以自强不息; 地势坤,君子以厚德载物;
  • 相关阅读:
    读书笔记 《如何阅读一本书》
    蓝桥杯 试题 历届试题 翻硬币 反转(开关问题)
    读书笔记 《如何阅读一本书》
    蓝桥杯 试题 历届试题 高僧斗法 博弈论
    读书笔记 《如何阅读一本书》
    蓝桥杯 试题 历届试题 格子刷油漆
    读书笔记 《如何阅读一本书》
    读书笔记 《如何阅读一本书》
    读书笔记 《如何阅读一本书》
    读书笔记 《如何阅读一本书》
  • 原文地址:https://www.cnblogs.com/mchao/p/14358704.html
Copyright © 2020-2023  润新知