在WPF中使用CefSharp浏览器时,是否有多次调用RegisterAsyncJsObject?

时间:2017-08-29 08:50:09

标签: c# wpf cefsharp

我在我的一个开源项目中使用CefSharp浏览器;降价编辑器,用于预览降价,如下面的屏幕截图所示: enter image description here

相关的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;
    }
}

我摆脱了错误,但现在滚动只在第一个标签中工作,并且它在其余标签中不起作用。

我的问题是;我可以以某种方式将“注册”转移到第二个选项卡(如果有多个选项卡,则为活动选项卡),以便从浏览器到文本框的滚动同步有效吗?

0 个答案:

没有答案