上一篇 https://www.cnblogs.com/mchao/p/13914726.html 简单了解了CefSharp引用配置但页面光秃秃的,这一篇着手开发简单浏览器窗体
一、Edge浏览器窗体分析
如上图所示可先将浏览器窗体分为两大部分,Header及Body部分,Header暂时分为Tab展示及搜索部分 每个Tab页有一个搜索及ChromiumWebBrowser
此时我们需要一个带关闭按钮的TabControl
二、自定义TabControl
修改TabItem ControlTemplate增加Button,关于TabControl分析请参考 Cys_Control(四) MTabControl
<Button Grid.Column="1" Style="{StaticResource TabCloseButton}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MTabControl}},Path=TabItemRemoveCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}" />
CommandParamenter 参数传当前 TabItem
在cs文件中添加依赖属性TabItemRemoveCommand
public static readonly DependencyProperty TabItemRemoveCommandProperty = DependencyProperty.Register("TabItemRemoveCommand", typeof(ICommand), typeof(MTabControl), new PropertyMetadata(null)); public ICommand TabItemRemoveCommand { get => (ICommand)GetValue(TabItemRemoveCommandProperty); set => SetValue(TabItemRemoveCommandProperty, value); }
并为TabItemRemoveCommand添加移除方法
private void TabItemRemove(object obj) { if (obj is TabItem item) { this.Items.Remove(item); } }
有了移除还需要有新增
在 TabControl中添加 Button,原理同移除
<Button Grid.Column="1" Style="{StaticResource TabAddButton}" HorizontalAlignment="Left" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MTabControl}},Path=TabItemAddCommand}"/>
三、添加搜索框
由图可知 Edge 搜索框由 三部分组成即(左右按钮及中间文本),相当于TextBox中增加了俩按钮,因此我们对TextBox做个扩展
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="auto"/> </Grid.ColumnDefinitions> <Grid Grid.Column="0"> <Button Style="{DynamicResource Button.NavigationSearch}" Margin="2,0"/> </Grid> <Grid Grid.Column="1"> <ScrollViewer x:Name="PART_ContentHost" FontSize="{TemplateBinding FontSize}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" BorderThickness="0" IsTabStop="False" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="4,0"/> <!--水印--> <TextBlock x:Name="Part_Watermark" Text="{TemplateBinding Watermark}" FontSize="{TemplateBinding FontSize}" Visibility="Hidden" HorizontalAlignment="Left" Foreground="{DynamicResource ColorBrush.FontWatermarkColor}" IsHitTestVisible="False" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="5,0"/> </Grid> <Grid Grid.Column="2"> <ToggleButton Style="{DynamicResource ToggleButton.NavigationCollection}" Margin="2,0"/> </Grid> </Grid>
文本框中左边增加Button,右边增加ToggleButton来区分是否网页已收藏(注:本次不加入业务处理)
关于TextBox水印及其他处理 请参照 Cys_Control(三) MTextBox
四、调整布局
增加前进回退刷新等按钮用于占位并调整搜索框
<Grid Grid.Row="0" Background="{DynamicResource WebBrowserBrushes.TabHeaderIsSelectedBackground}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <StackPanel Grid.Column="0" Orientation="Horizontal"> <Button Style="{DynamicResource Button.NavigationBack}"/> <Button Style="{DynamicResource Button.NavigationForward}"/> <Button Style="{DynamicResource Button.NavigationRefresh}"/> </StackPanel> <controls:MTextBox Grid.Column="1" Watermark="搜索或输入Web地址" x:Name="SearchText"/> <Grid Grid.Column="2" MinWidth="150"> </Grid> </Grid>
此时从页面上看已经有些像浏览器了,跑起来。。。
此时发现点击网页链接和预想的打开新Tab页有些差距
五、新Tab页打开链接
Cef的Popup处理定义在ILifeSpanHandler接口中,若要阻止弹窗并使用自己的Tab页则应该自定义LifeSpanHandler
新增CustomLifeSpanHandler类并实现ILifeSpanHandler接口
public class CustomLifeSpanHandler : ILifeSpanHandler { public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser) { if (chromiumWebBrowser is CustomWebBrowser webBrowser) { webBrowser.OpenNewTab(targetUrl); } newBrowser = null; return true; } public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser) { } public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser) { return false; } public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser) { } }
OnBeforePopup方法中可以取到 targetUrl也就是点击的<a>标签中的链接
此时我们需要将targetUrl传递到WebBrowser中,由于我们需要打开Tab页,需要增加一个方法 OpenNewTab(targetUrl),
ChromiumWebBrowser类并不能满足我们的使用场景,故扩展ChromiumWebBrowser类,新增CustomWebBrowser继承于ChromiumWebBrowser
并添加 OpenNewTab方法
public void OpenNewTab(string url) { Dispatcher.Invoke(() => { var tabControl = ControlHelper.FindVisualParent<MTabControl>(this); tabControl?.TabItemAddCommand?.Execute(url); }); }
该方法用于新增一个Tab页。
运行看效果