基於CefSharp開發(七)瀏覽器收藏夾選單
一、Edge收藏夾選單分析
如下圖所示為Edge收藏夾選單, 點選收藏夾選單按鈕(紅框部分)彈出收藏夾選單窗體,窗體中包含工具欄(綠框部分)和樹型選單(黃框部分)
工具欄按鈕功能分別為添加當前網頁到根節點、建立新資料夾到根節點、搜尋收藏夾內容、單中單(收藏夾選單中的其他功能)、收藏夾選單固定到右側
在樹節點上右鍵,有如下右鍵選單功能
要完成此功能,需先仿其形,再謀其神。
二、仿其形
這裡所謂的仿其形,即模仿它的樣式(Style)
1、建立收藏夾選單UserControl
建立FavoritesMenuUc,Grid內容如下:ToggleButton控制選單顯隱,Popup展示彈出選單,
StackPanel 中新增五個按鈕用於實現工具欄中的功能,MTreeView用於實現樹型選單
關於MTreeView的實現請參照 Cys_Control(六) MTreeView
<Grid> <ToggleButton x:Name="FavoritesButton" Style="{DynamicResource ToggleButton.FontButton}" Checked="FavoritesButton_OnChecked" Unchecked="FavoritesButton_OnUnchecked" Content="" FontSize="26" Background="Transparent" IsChecked="{Binding ElementName=FavoritesPop,Path=IsOpen}"/> <Popup x:Name="FavoritesPop" PopupAnimation="Fade" Placement="Bottom" PlacementTarget="{Binding ElementName=FavoritesButton}" StaysOpen="False" AllowsTransparency="True" HorizontalOffset="-330"> <Border Background="{DynamicResource WebBrowserBrushes.WebMenuBackground}" CornerRadius="5"> <Border.Effect> <DropShadowEffect Color="{DynamicResource Color.MenuItemDropShadowBrush}" Opacity="0.3" ShadowDepth="3"/> </Border.Effect> <Grid Width="360" Height="660"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="1"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid Grid.Row="0" Height="40"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="收藏夾欄" VerticalAlignment="Center" FontSize="18" Margin="10,0,0,0" Foreground="{DynamicResource WebBrowserBrushes.DefaultForeground}"/> <StackPanel Grid.Column="2" Orientation="Horizontal" Margin="0,0,10,0"> <Button Style="{DynamicResource Button.FontButton}" Content=""/> <Button Style="{DynamicResource Button.FontButton}" Content=""/> <Button Style="{DynamicResource Button.FontButton}" Content=""/> <Button Style="{DynamicResource Button.FontButton}" Content="..." Padding="0,0,0,12"/> <Button Style="{DynamicResource Button.FontButton}" Content=""/> </StackPanel> </Grid> <Rectangle Grid.Row="1" Height="1" Fill="{DynamicResource WebBrowserBrushes.WebMenuDivideLine}"/> <controls:MTreeView Grid.Row="2" x:Name="FavoritesTree"/> </Grid> </Border> </Popup> </Grid>
新建類TreeNode用於顯示TreeView顯示
public class TreeNode { public int NodeId { get; set; } public int ParentId { get; set; } public string NodeName { get; set; } public string Url { get; set; } = "http://www.baidu.com"; public List<TreeNode> ChildNodes { get; set; } = new List<TreeNode>(); public int Type { get; set; } //0-檔案,1-資料夾 }
FavoritesMenuUc.xaml.cs檔案中增加測試資料
private void GetFavoritesInfo() { nodes = new List<TreeNode>() { new TreeNode(){ParentId=-1, NodeId=0, NodeName = "收藏夾",Type = 1}, new TreeNode(){ParentId=0, NodeId=1, NodeName = "文字",Type = 1}, new TreeNode(){ParentId=0, NodeId=2, NodeName = "音訊",Type = 1}, new TreeNode(){ParentId=0, NodeId=3, NodeName = "視訊",Type = 1}, new TreeNode(){ParentId=1, NodeId=11, NodeName = "文字1",Type = 0}, new TreeNode(){ParentId=1, NodeId=12, NodeName = "文字2",Type = 0}, new TreeNode(){ParentId=1, NodeId=13, NodeName = "文字3",Type = 0}, }; List<TreeNode> root = GetNodes(-1, nodes); AddTreeViewItems(null, root[0], 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; } private void AddTreeViewItems(MTreeViewItem parent, TreeNode treeNode, bool isRoot) { var treeViewItem = new MTreeViewItem(); if (treeNode.ChildNodes.Count <= 0) { if (treeNode.Type == 0) { treeViewItem.Header = treeNode.Url; treeViewItem.Icon = "\ueb1e"; treeViewItem.IsExpandedIcon = "\ueb1e"; treeViewItem.IconForeground = new SolidColorBrush(Color.FromRgb(255, 255, 255)); } else { treeViewItem.Header = treeNode.NodeName; } } else { treeViewItem.Header = treeNode.NodeName; foreach (var child in treeNode.ChildNodes) { AddTreeViewItems(treeViewItem, child, false); } } if (!isRoot) parent.Items.Add(treeViewItem); else { FavoritesTree.Items.Add(treeViewItem); } }
執行效果如下:
2、為MTreeView新增右鍵選單
右鍵子選單可使用MMneuItem,xaml樣式如下
<controls:MTreeView Grid.Row="2" x:Name="FavoritesTree" ContextMenuOpening="FavoritesTree_OnContextMenuOpening"> <controls:MTreeView.ContextMenu> <ContextMenu x:Name="FavoritesContextMenu" Style="{DynamicResource WebCustomMenus.DefaultContextMenu}"> <controls:MMenuItem Tag="0" Header="全部開啟(16個)" Icon=""/> <controls:MMenuItem Tag="1" Header="在新建視窗中全部開啟(16個)" Icon=""/> <controls:MMenuItem Tag="2" Header="在新 InPrivate視窗全部開啟(16個)" Icon=""/> <controls:MMenuItem Tag="4" Header="按名稱排序" Icon=""/> <controls:MMenuItem Tag="5" Header="重新命名" Icon=""/> <controls:MMenuItem Tag="5" Header="刪除" Icon="" IconFontSize="26"/> <controls:MMenuItem Tag="5" Header="將當前標籤頁新增到資料夾" Icon=""/> <controls:MMenuItem Tag="5" Header="將所有標籤頁新增到資料夾"/> <controls:MMenuItem Tag="5" Header="新增資料夾" Icon=""/> </ContextMenu> </controls:MTreeView.ContextMenu> </controls:MTreeView>
當右鍵未選中時增加遮蔽右鍵選單
private void FavoritesTree_OnContextMenuOpening(object sender, ContextMenuEventArgs e) { _currentRightItem = ControlHelper.FindVisualParent<MTreeViewItem>(e.OriginalSource as DependencyObject); if (null == _currentRightItem) { e.Handled = true; } }
執行效果如下:
三、謀其神
這裡的謀其神,就是使其可以完成正常的業務處理。
前面仿造了Edge瀏覽器的大致樣式,接下來要對及增加資料儲存、命令處理等
1、增加Favorites資料儲存
這裡使用同資料下載同樣的處理邏輯,將收藏夾儲存為Json檔案
新建FavoritesDataRepository,類中新增 SaveFavoritesSetting、GetFavoritesSetting用於儲存與讀取資料。
public class FavoritesDataRepository { public void SaveFavoritesSetting() { try { var setting = GlobalInfo.FavoritesSetting; if (setting == null) return; var fileName = FileDataPath.GetFilePath(DataFileType.Favorites); CommonOperator.SaveDataJson(setting, fileName); } catch (Exception ex) { } } public FavoritesSetting GetFavoritesSetting() { var fileName = FileDataPath.GetFilePath(DataFileType.Favorites); var setting = CommonOperator.GetDataJson<FavoritesSetting>(fileName); setting ??= new FavoritesSetting(); setting.FavoritesInfos ??= new List<TreeNode>(); if (setting.FavoritesInfos.Count <= 0) { setting.FavoritesInfos.Add(new TreeNode() { ParentId = -1, NodeId = 0, NodeName = "收藏夾", Type = 1, }); } return setting; } }
2、增加選單事件
由於事件較多,目前僅處理新增資料夾、新增收藏、刪除功能
新增folder,這裡的if用來判斷是收藏夾工具欄的按鈕還是右鍵選單C
private void AddFolder_OnClick(object sender, RoutedEventArgs e) { if (sender is Button) { var newTreeNode = GetNewTreeNodeInfo(true, 1, "新建資料夾", null); if (null == FavoritesTree || FavoritesTree.Items.Count <= 0) return; var treeNodeUc = FavoritesTree.Items[0]; if (!(treeNodeUc is MTreeViewItem item)) return; item.Items.Add(newTreeNode.Item2); GlobalInfo.FavoritesSetting.FavoritesInfos.Add(newTreeNode.Item1); } else if (sender is MMenuItem) { var newTreeNode = GetNewTreeNodeInfo(false, 1, "新建資料夾", null); if (_currentRightItem != null && _currentRightItem.Type == 1) { _currentRightItem.Items.Add(newTreeNode.Item2); GlobalInfo.FavoritesSetting.FavoritesInfos.Add(newTreeNode.Item1); } } }
新增收藏,新增收藏增加了GetWebUrlEvent事件 用於獲取當前tab頁的url;
private void AddFavorites_OnClick(object sender, RoutedEventArgs e) { var model = GetWebUrlEvent?.Invoke(); if (null == model) return; if (sender is Button) { if (!(FavoritesTree.Items[0] is MTreeViewItem item)) return; var newTreeNode = GetNewTreeNodeInfo(true, 0, model.Title, model.CurrentUrl); GlobalInfo.FavoritesSetting.FavoritesInfos.Add(newTreeNode.Item1); item.Items.Add(newTreeNode.Item2); } else if (sender is MMenuItem) { if (_currentRightItem != null && _currentRightItem.Type == 1) { var newTreeNode = GetNewTreeNodeInfo(false, 0, model.Title, model.CurrentUrl); _currentRightItem.Items.Add(newTreeNode.Item2); GlobalInfo.FavoritesSetting.FavoritesInfos.Add(newTreeNode.Item1); } } }
刪除當前節點
private void Delete_OnClick(object sender, RoutedEventArgs e) { if (_currentRightItem?.Parent == null) return; foreach (var item in _currentRightItem.Items) { _currentRightItem.Items.Remove(item); if (!GlobalInfo.FavoritesSetting.FavoritesInfos.Exists(x => x.NodeId == _currentRightItem.NodeId)) continue; var currentNode = (GlobalInfo.FavoritesSetting.FavoritesInfos.FirstOrDefault(x => x.NodeId == _currentRightItem.NodeId)); GlobalInfo.FavoritesSetting.FavoritesInfos.Remove(currentNode); } if (_currentRightItem.Parent is MTreeViewItem 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); } }
關於建立TreeNode程式碼細節請參考文章末尾原始碼
增加OpenNewTabEvent事件用於點選收藏內容時開啟網頁
四、執行效果
五、原始碼地址
gitee地址:https://gitee.com/sirius_machao/mweb-browser