捕获显示PDF文档的WPF WebBrowser控件中的单击事件

本文关键字:控件 单击 事件 WebBrowser WPF 显示 PDF 文档 | 更新日期: 2023-09-27 17:50:47

我正在开发一个Windows WPF应用程序,它使用默认的WebBrowser控件(System.Windows.Controls.WebBrowser)来嵌入网页。使用WPF控件底层的COM对象,我可以根据需要操作控件内加载的每个HTML文档。作为一个例子,下面是我用来获取COM对象句柄的代码片段:

public void HookInputElementForKeyboard()
{
    HTMLDocument htmlDocument = (HTMLDocument)webBrowserControl.Document;
    var inputElements = htmlDocument.getElementsByTagName("input");
    HTMLDocumentEvents_Event documentEvents = (HTMLDocumentEvents_Event) htmlDocument;
    documentEvents.onclick += documentEvents_onclick;
    DeregisterAll();
    foreach (var item in inputElements)
    {
        DispHTMLInputElement inputElement = item as DispHTMLInputElement;
        if (inputElement.type == "text" || inputElement.type == "password" || inputElement.type == "search")
        {
            HTMLButtonElementEvents_Event htmlButtonEvent = inputElement as HTMLButtonElementEvents_Event;
            this.hookedElements.Add(htmlButtonEvent);
            htmlButtonEvent.onclick += InputOnClickHandler;
            htmlButtonEvent.onblur += InputOnBlurHandler;
        }
    }
}

我使用依赖从Microsoft.mshtml.dll。这里我将处理程序附加到DOM元素的事件上,以便能够在。net代码中管理它们(onclick和onblur事件)。

有了这个对象(HTMLDocument),我几乎可以克服WPF控件的所有限制。当WebBrowser控件导航到PDF文档(即响应MIME类型是application/PDF)时,我的问题出现了。在这种情况下,我必须假设使用默认的adobereader插件来显示PDF(这是我的目标机器必须的行为方式)。我仍然可以获得与以下内容一起使用的底层AcroRead ActiveX的句柄:
private void HookHtmlDocumentOnClick()
{
    var document = (IAcroAXDocShim)WebBrowserControl.Document;
    // Just a test
    var obj = document as AcroPDF;
    obj.OnMessage += obj_OnMessage;
}

在我添加适当的依赖到项目(Interop.AcroPDFLib.dll)

但是在这一点上,我不知道是否有一种方法来注册发生在文档上的鼠标事件。我所要做的就是处理PDF文档上的click事件。

当然,使用下面的

是行不通的。事件不会冒泡到。net代码级别。

WebBrowserControl.MouseDown += WebBrowserControl_MouseDown;

有没有人知道是否有一种方法来挂钩IAcroAXDocShim,以便处理鼠标点击事件?有其他的选择吗?我应该选择一条完全不同的道路吗?是否直接使用AcroRead ActiveX给我一些优势比目前的情况?

捕获显示PDF文档的WPF WebBrowser控件中的单击事件

我最终采用了另一种方法。每当识别PDF内容时,我决定切换到不同的UserControl,而不是WPF WebBrowser。我知道在开发Windows Store应用程序时,PDF渲染的一些类和API是可用的,所以我应用了一个解决方案,以便在我的WPF应用程序中使用这些类。

首先,我编辑了csproj文件,添加了以下标记作为<PropertyGroup>的子标记:

<TargetPlatformVersion>8.1</TargetPlatformVersion>

,那么在"添加引用"对话框中应该出现一个名为"Windows 8.1"的部分。我将这部分的唯一汇编添加到参考资料中。为了使解决方案工作,可能需要更多的程序集:

  • 系统。IO
  • 系统。运行时
  • System.Runtime.InteropServices
  • System.Runtime.InteropServices.WindowsRuntime
  • System.Runtime.WindowsRuntime
  • 系统。线程
  • System.Threading.Tasks
有了这些之后,我编写了一个呈现方法,它遍历PDF文件的各个页面,并为每个页面创建一个png文件。然后我将页面添加到StackPanel中。在这一点上,你可以像管理任何元素一样管理StackPanel上的Click(或MouseDown)事件。下面是一个简单的呈现方法示例:
async private void RenderPages(String pdfUrl)
{
    try
    {
        HttpClient client = new HttpClient();
        var responseStream = await client.GetInputStreamAsync(new Uri(pdfUrl));
        InMemoryRandomAccessStream inMemoryStream = new InMemoryRandomAccessStream();
        using (responseStream)
        {
            await responseStream.AsStreamForRead().CopyToAsync(inMemoryStream.AsStreamForWrite());
        }
        var pdf = await PdfDocument.LoadFromStreamAsync(inMemoryStream);
        if (pdf != null && pdf.PageCount > 0)
        {
            AddPages(pdf);
        }
    }
    catch (Exception e)
    {
        throw new CustomException("An exception has been thrown while rendering PDF document pages", e);
    }
}

async public void AddPages(PdfDocument pdfDocument)
{
    PagesStackPanel.Children.Clear();
    if (pdfDocument == null || pdfDocument.PageCount == 0)
    {
        throw new ArgumentException("Invalid PdfDocument object");
    }
    var path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
    StorageFolder rootFolder = await StorageFolder.GetFolderFromPathAsync(path);
    var storageItemToDelete = await rootFolder.TryGetItemAsync(Constants.LOCAL_TEMP_PNG_FOLDER);
    if (storageItemToDelete != null)
    {
        await storageItemToDelete.DeleteAsync();
    }
    StorageFolder tempFolder = await rootFolder.CreateFolderAsync(Constants.LOCAL_TEMP_PNG_FOLDER, CreationCollisionOption.OpenIfExists);
    for (uint i = 0; i < pdfDocument.PageCount; i++)
    {
        logger.Info("Adding PDF page nr. " + i);
        try
        {
            await AppendPage(pdfDocument.GetPage(i), tempFolder);
        }
        catch (Exception e)
        {
            logger.Error("Error while trying to append a page: ", e);
            throw new CustomException("Error while trying to append a page: ", e);
        }
    }
}