我在我的一个开源项目中使用CefSharp浏览器;降价编辑器,用于预览降价,如下面的屏幕截图所示:
相关的XAML如下:
<dragablz:TabablzControl TabStripPlacement="Top" Margin="5" ItemsSource="{Binding Documents}" SelectedItem="{Binding CurrentDocument, Mode=TwoWay}" x:Name="TabDocuments" FixedHeaderCount="{Binding CurrentPreferences.IsTabBarLocked, Converter={StaticResource LockTabBarConverter}}">
<dragablz:TabablzControl.HeaderItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10" MaxWidth="10" MinWidth="10"/>
<ColumnDefinition Width="10" MaxWidth="10" MinWidth="10"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Metadata.FileName}"/>
<Thumb Grid.Column="0" Style="{DynamicResource InvisibleThumbStyle}" dragablz:DragablzItem.IsCustomThumb="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding CloseDocumentButtonCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Thumb>
<TextBlock Grid.Column="1" Text="*" Visibility="{Binding IsSaved, Converter={StaticResource VisibilityConverter}}"/>
<Button Grid.Column="2" Width="10" Height="10" MaxWidth="10" MaxHeight="10" MinWidth="10" MinHeight="10" VerticalAlignment="Center" HorizontalAlignment="Right" Command="{Binding CloseDocumentButtonCommand}">
<TextBlock Text="X" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="8" FontWeight="Bold"/>
</Button>
</Grid>
</DataTemplate>
</dragablz:TabablzControl.HeaderItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate x:Name="TabDocumentsDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border BorderBrush="Black" BorderThickness="1" Grid.Column="0" Margin="5">
<customControls:CodeTextboxHost Text="{Binding Markdown, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
History="{Binding History, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
RedoStack="{Binding RedoStack, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
FilePath="{Binding Metadata.FilePath}"
WordWrap="{Binding IsWordWrap, UpdateSourceTrigger=PropertyChanged}"
Font="{Binding CurrentFont, UpdateSourceTrigger=PropertyChanged}"
x:Name="CodeTextboxHost"/>
</Border>
<Border BorderBrush="Black" BorderThickness="1" Grid.Column="1" Margin="5">
<wpf:ChromiumWebBrowser Address="{Binding Html, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="ChromiumWebBrowser" Loaded="ChromiumWebBrowser_OnLoaded"/>
</Border>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</dragablz:TabablzControl>
我现在正在实现滚动同步。然而,它不是非常简单,因为不可能与浏览器滚动条作为正常控件进行交互。幸运的是,CefSharp浏览器提供了一种运行JavaScript并将某些类与某些JavaScript对象链接起来的方法。我能够使用这些方法实现从文本框控件到浏览器的滚动同步。
但是,从浏览器到文本框控件实现滚动同步时,我遇到了问题。我将简要介绍我迄今为止所做的工作。
在每个文档的HTML文件中,我都有以下脚本:
window.onscroll = function (e) {
var maxValue = document.getElementsByTagName('body')[0].scrollHeight - document.getElementsByTagName('body')[0].clientHeight;
var minValue = 0;
var value = e.target.body.scrollTop;
cefChromimumBrowser.browserScrollChange(value, maxValue, minValue);
}
此脚本获取最大值,最小值和实际滚动值,并将其发送到C#端。为了进行“传输”,我有一个事件监听器,它在首次加载浏览器时执行以下操作:
private void ChromiumWebBrowser_OnLoaded(object sender, RoutedEventArgs e)
{
var browser = (ChromiumWebBrowser)sender;
browser.RegisterAsyncJsObject("cefChromimumBrowser", CefChromiumBrowserManager.GetInstance());
}
这样,将我在JavaScript中的cefChromimumBrowser
对象注册为CefChromiumBrowserManager
的实例。在CefChromiumBrowserManager
我有一个这样的方法:
public void BrowserScrollChange(int value, int maxValue, int minValue)
{
var scrollResult = new ScrollResult
{
MaxValue = maxValue,
MinValue = minValue,
Value = value
};
SharedEventHandler.GetInstance().RaiseOnBrowserScrollChanged(scrollResult);
}
当引发OnBrowserScrollChanged
事件时,它会更改文本框控件上的滚动位置。
当只有一个标签时,这非常有效。当我打开另一个选项卡时,我得到了“浏览器已经初始化。必须在创建基础CEF浏览器之前调用RegisterJsObject。”错误。
我检查了CefSharp文档,确实如此,每个应用程序初始化浏览器一次,讨论here。并且只能在首次初始化浏览器后立即使用RegisterAsyncJsObject,记录为here。
所以我尝试了第二种方法,想一想如果注册的JavaScript是相同的,它会在不重新注册的情况下接收它:
private void ChromiumWebBrowser_OnLoaded(object sender, RoutedEventArgs e)
{
if (!_isBrowserInitialized)
{
var browser = (ChromiumWebBrowser)sender;
browser.RegisterAsyncJsObject("cefChromimumBrowser", CefChromiumBrowserManager.GetInstance());
_isBrowserInitialized = true;
}
}
我摆脱了错误,但现在滚动只在第一个标签中工作,并且它在其余标签中不起作用。
我的问题是;我可以以某种方式将“注册”转移到第二个选项卡(如果有多个选项卡,则为活动选项卡),以便从浏览器到文本框的滚动同步有效吗?