2015-07-14 4 views
2

Привет, мне нужно создать настраиваемое контекстное меню для управления веб-браузером в wpf. Вот мой код xaml, который не работает:Пользовательское контекстное меню для WPF WebBrowser Control

<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> 

Я скопировал код контекстного меню из другого места. Это работает в других элементах управления, но не для управления веб-браузером. Можно ли сделать эту работу?

ответ

2

Нет, эта работа невозможна.
Управление WebBrowser - очень тонкая оболочка вокруг собственного компонента ActiveX WebBrowser, который является частью подсистемы Internet Explorer. Он размещен в собственном оконном хосте (окно WPF и WebBrowser имеют разные HWND), поэтому WPF знает только о том, что фокус входит и выходит из WebBrowser, но не знает о каких-либо событиях клавиатуры и мыши. Кроме того, существует так называемая проблема «воздушного пространства»: WPF-рендеринг и внутренние области экрана не могут пересекаться.
Поэтому вы не можете использовать WPF ContextMenu с WebBrowser, потому что:

  1. WPF не получает Щелчок правой кнопкой мыши событие, чтобы открыть контекстное меню,
  2. WPF не может сделать контекстное меню над WebBrowser

Также , Я не думаю, что есть простой способ эмуляции ContextMenu с html/js в содержимом браузера. Насколько я помню, компонент ActiveX использует режим рендеринга IE5 (quirk), и это невозможно изменить, не изменяя файлы реестра.
Вы можете попробовать использовать ActiveX API с объектом WebBrowser.Document, чтобы отключить собственное контекстное меню и сделать еще один с помощью WinAPI, что непросто.
Таким образом, я бы рекомендовал искать другие, чисто WPF управления браузера или HTML-рендеров, такие как awesomium

2

Привет Вы должны добавить ссылку на библиотеку объектов 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; 
    } 
    } 
} 
+0

Привет спасибо за Ваш ответ. В конечном итоге я решил это, включив управление браузером и элемент управления xaml. Мы предлагаем пользователю переключаться между браузером и контролем xaml. На данный момент пользователям нравится решение. – Luke101

+0

проблема решения заключается в том, что он работает один раз - если вы щелкните правой кнопкой мыши на полосе прокрутки, например, или выберите пользовательский пункт меню - в следующий раз, когда вы щелкните правой кнопкой мыши по WebBrowser, вы получите стандартное меню IE ... :-( –

0

Часть 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 
} 
+0

проблема решения заключается в том, что он работает один раз - если вы щелкните правой кнопкой мыши на полосе прокрутки, например, или выберите пользовательский пункт меню - в следующий раз, когда вы щелкните правой кнопкой мыши по WebBrowser, вы получите стандартное меню IE ... :-( –

+0

Я не уверен, почему вы столкнулись с этой проблемой, вы должны убедиться, что вы возвращаетесь к истинному для своего пользовательского контекстного меню, чтобы не появляться. Никакая причина, почему он покажет вам меню IE по умолчанию .... Поделитесь своим кодом и, возможно, я может указать вам в правильном направлении .... – Devdude

+0

Я использовал код @ MartinHoly ... я добавил здесь ответ, как это сделать, пожалуйста, проверьте это. Не успевайте и не решитесь выяснить, почему это так поступайте, хотя ... –

0

Я принял решение, предоставленное @MartinHoly, и я столкнулся с проблемой: в контекстное меню можно вывести только один раз (если вы щелкнете правой кнопкой мыши по полосе прокрутки, например, или выберите пользовательский пункт меню - в следующий раз вы щелкните правой кнопкой мыши веб-браузер, чтобы добавить стандартное меню IE).Я сделал следующее временное решение: The 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; 
    } 
    } 
} 
Смежные вопросы