簡體   English   中英

WPF WebBrowser 控件的自定義上下文菜單

[英]Custom context menu for WPF WebBrowser Control

您好,我需要為 wpf 中的 web 瀏覽器控件創建一個自定義上下文菜單。這是我的 xaml 代碼,它不起作用:

<WebBrowser x:Name="EmailBox"  ap:BrowserBehavior.HtmlString="{Binding Message, Mode=OneWay}">
    <WebBrowser.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Copy" Command="ApplicationCommands.Copy"/>
            <MenuItem Header="Copy to Customer Reference ID" 
                  Command="{Binding CopyID}"
                  CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, 
                  Path=PlacementTarget.Selection.Text}">
                <MenuItem.Icon>
                    <Image Source="{StaticResource CopyImageSource}" Width="16" />
                </MenuItem.Icon>
            </MenuItem>
            <MenuItem Header="Copy to Comments"
                  Command="{Binding CopyToCommentsCommand}"
                  CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, 
                  Path=PlacementTarget.Selection.Text}">
                <MenuItem.Icon>
                    <Image Source="{StaticResource NoteCopyI}" Width="16" />
                </MenuItem.Icon>
            </MenuItem>
        </ContextMenu>
    </WebBrowser.ContextMenu>
</WebBrowser>

我從其他地方復制了上下文菜單代碼。 這適用於其他控件,但不適用於網絡瀏覽器控件。 有可能使這項工作嗎?

嗨,您必須添加對Microsoft HTML對象庫的引用,然后...

XAML

<Window x:Class="WPFCustomContextMenuInWebBrowser.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFCustomContextMenuInWebBrowser"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
  <Window.Resources>
    <ContextMenu x:Key="MnuCustom" StaysOpen="True">
      <MenuItem Header="Custom 1"></MenuItem>
      <MenuItem Header="Custom 1"></MenuItem>
      <MenuItem Header="Custom 3"></MenuItem>
    </ContextMenu>
  </Window.Resources>
    <Grid>
        <WebBrowser x:Name="Wb"></WebBrowser>
    </Grid>
</Window>

C#

using System.Windows.Controls;
using MSHTML;

namespace WPFCustomContextMenuInWebBrowser {
  public partial class MainWindow {
    private HTMLDocumentEvents2_Event _docEvent;
    public MainWindow() {
      InitializeComponent();
      Wb.Navigate("http://google.com");
      Wb.LoadCompleted += delegate {
        if (_docEvent != null) {
          _docEvent.oncontextmenu -= _docEvent_oncontextmenu;
        }
        if (Wb.Document != null) {
          _docEvent = (HTMLDocumentEvents2_Event)Wb.Document;
          _docEvent.oncontextmenu += _docEvent_oncontextmenu;
        }
      };
    }

    bool _docEvent_oncontextmenu(IHTMLEventObj pEvtObj) {
      WbShowContextMenu();
      return false;
    }

    public void WbShowContextMenu() {
      ContextMenu cm = FindResource("MnuCustom") as ContextMenu;
      if (cm == null) return;
      cm.PlacementTarget = Wb;
      cm.IsOpen = true;
    }
  }
}

不,這是不可能的。
WebBrowser控件是本機WebBrowser ActiveX組件的非常薄的包裝,該組件是Internet Explorer子系統的一部分。 它托管在其自己的窗口主機中(WPF窗口和WebBrowser具有不同的HWND),因此WPF僅了解焦點進入和離開WebBrowser的知識,但不了解任何鍵盤/鼠標事件。 此外,還有一個所謂的“空域問題”:WPF渲染的屏幕區域和本機區域不能重疊。
因此,不能將WPF ContextMenu與WebBrowser一起使用,因為:

  1. WPF不接收鼠標右鍵單擊事件以打開上下文菜單
  2. WPF無法在WebBrowser上方繪制上下文菜單

另外,我認為沒有簡單的方法可以在瀏覽器的內容中使用html / js來模擬ContextMenu-我記得,ActiveX組件使用IE5(古怪的)渲染模式,並且不更改注冊表文件就無法更改它。
您可以嘗試將ActiveX API與WebBrowser.Document對象一起使用以禁用本機上下文菜單,並通過WinAPI自己繪制另一個菜單,這並非易事。
因此,我建議您尋找其他純WPF瀏覽器控件或HTML渲染器,例如awesomium

XAML如下:

<!--WebBrowser to Display Chat Messages-->
    <WebBrowser Name="webBrowser"
                    Source="http://stakoverflow.com"                        
                    Navigated="webBrowser_Navigated"
                    Navigating="webBrowser_Navigating"
                    LoadCompleted="webBrowser_LoadCompleted">
        <WebBrowser.ContextMenu>
            <ContextMenu x:Name="wbContextMenu" >
                <MenuItem x:Name="menuItem1" Header="Test Item" Click="menuItem1_Click" />
            </ContextMenu>
        </WebBrowser.ContextMenu            
    </WebBrowser>

代碼如下:

using mshtml;

private mshtml.HTMLDocumentEvents2_Event documentEvents;

在構造函數或xaml中設置您的LoadComplete事件:

webBrowser.LoadCompleted += webBrowser_LoadCompleted;

然后在該方法中創建新的Webbrowser文檔對象,並查看可用屬性並創建新事件,如下所示:

private void webBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
    documentEvents = (HTMLDocumentEvents2_Event)webBrowserChat.Document; // this will access the events properties as needed
    documentEvents.oncontextmenu += webBrowserChat_ContextMenuOpening;
}

private bool webBrowserChat_ContextMenuOpening(IHTMLEventObj pEvtObj)
{
    wbContextMenu.PlacementTarget = pEvtObj as ContextMenu; // Creates target spot where contextmenu will appear
    wbContextMenu.IsOpen = true; // Opens contextmneu
    return false; // ContextMenu wont open
    // return true;  ContextMenu will open
    // Here you can create your custom contextmenu or whatever you want
}

我采用了@MartinHoly提供的解決方案,但遇到了問題:上下文菜單只能彈出一次(例如,如果右鍵單擊滾動條,或者選擇自定義菜單項-下次您右鍵單擊WebBrowser,將顯示標准IE菜單)。 我做了以下解決方法:xaml:

<Window x:Class="WPFCustomContextMenuInWebBrowser.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WPFCustomContextMenuInWebBrowser"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <ContextMenu x:Key="MnuCustom" StaysOpen="True">
      <MenuItem Header="Custom 1"></MenuItem>
      <MenuItem Header="Custom 2"></MenuItem>
      <MenuItem Header="Custom 3"></MenuItem>
    </ContextMenu>
  </Window.Resources>
<Grid>
    <WebBrowser x:Name="Browser"></WebBrowser>
</Grid>

后面的代碼:

using System.Windows.Controls;
using MSHTML;

namespace WPFCustomContextMenuInWebBrowser {
  public partial class MainWindow {

    public MainWindow() 
    {
      InitializeComponent();
      Browser.LoadCompleted += BrowserOnLoadCompleted;
    }

    void BrowserOnLoadCompleted(object sender, NavigationEventArgs navigationEventArgs)
    {
        var mshtmlDoc = Browser.Document as HTMLDocument;
        if (mshtmlDoc == null) return;
                    var doc2event = mshtmlDoc as HTMLDocumentEvents2_Event;
        if (doc2event != null)
        {               
            doc2event.onfocusin += FocusInContextMenu;
        }            
    }

    bool OpenContextMenu(IHTMLEventObj pEvtObj)
    {
        WbShowContextMenu(pEvtObj as ContextMenu);
        return false;
    }

    void FocusInContextMenu(IHTMLEventObj pevtobj)
    {
        var mshtmlDoc = Browser.Document as HTMLDocument;
        var doc2event = mshtmlDoc as HTMLDocumentEvents2_Event;
        if (doc2event != null)
        {
            doc2event.oncontextmenu -= OpenContextMenu;
            doc2event.onfocusin -= FocusInContextMenu;
            doc2event.oncontextmenu += OpenContextMenu;
            doc2event.onfocusin += FocusInContextMenu;
        }
    }

    public void WbShowContextMenu() 
    {
      ContextMenu cm = FindResource("MnuCustom") as ContextMenu;
      if (cm == null) return;
      cm.PlacementTarget = Browser;
      cm.IsOpen = true;
    }
  }
}

我有一個間接實現,它涉及在 C# 和 javascript 中互相調用。

xaml:

    <WebBrowser x:Name="webbrowser">
        <WebBrowser.ContextMenu>
            <ContextMenu>
                <MenuItem Header="item1"/>
            </ContextMenu>
        </WebBrowser.ContextMenu>
    </WebBrowser>

c#:

    using System.Runtime.InteropServices;


    public MainWindow()
    {
        InitializeComponent();
        //webbrowser.Navigate(new Uri("https://www.google.com"));
        webbrowser.ObjectForScripting = new ScriptManager(this);
        webbrowser.LoadCompleted += Webbrowser_LoadCompleted;
    }

    private void Webbrowser_LoadCompleted(object sender, NavigationEventArgs e)
    {
        //call C# method and disable the default contextmenu here.
        webbrowser.InvokeScript("eval", new object[] { "document.oncontextmenu = function() { window.external.ShowContextMenu(); return false; };" });
    }

    [ComVisible(true)]
    public class ScriptManager
    {
        private MainWindow mainWindow;
        public ScriptManager(MainWindow MainWindow)
        {
            mainWindow = MainWindow;
        }
        public void ShowContextMenu()
        {
            mainWindow.webbrowser.ContextMenu.IsOpen = true;
        }
    }

但是當頁面加載時它仍然有一個本機上下文菜單,因為 LoadCompleted 事件尚未觸發。

所以如果html頁面是自己寫的,可以直接在html的腳本部分添加這行,不需要LoadCompleted事件:

document.oncontextmenu = function() { window.external.ShowContextMenu(); return false; };

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM