开发者

WPF WebBrowser control zoom in/out support?

开发者 https://www.devze.com 2023-03-13 09:47 出处:网络
For a WPF WebBrowser control, is there a way to dupli开发者_开发知识库cate Internet Explorer\'s zoom functionality?

For a WPF WebBrowser control, is there a way to dupli开发者_开发知识库cate Internet Explorer's zoom functionality?

In other words, Internet Explorer has the menu View > Zoom > 75%, which renders the web page at 75% scale. Is there a way to make a web browser control, which is embedded in a WPF app, do the same thing?

I've seen this post: WPF WebBrowser - How to Zoom Content?

But it only seems to scale the page and not the page content.


public partial class TestWindow: UserControl
{
    public TestWindow()
    {
        InitializeComponent();

        browser.LoadCompleted += new LoadCompletedEventHandler(browser_LoadCompleted);
    }

    private void browser_LoadCompleted(object sender, NavigationEventArgs e)
    {
        try
        {

            FieldInfo webBrowserInfo = browser.GetType().GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);

            object comWebBrowser = null;
            object zoomPercent = 120;
            if (webBrowserInfo != null)
                comWebBrowser = webBrowserInfo.GetValue(browser);
            if (comWebBrowser != null)
            {
                InternetExplorer ie = (InternetExplorer)comWebBrowser;
                ie.ExecWB(SHDocVw.OLECMDID.OLECMDID_OPTICAL_ZOOM, SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, ref zoomPercent, IntPtr.Zero);
            }
        }
        catch (Exception ex)
        {
        }
    }


    public void SetBrowser(string url)
    {
        browser.Navigate(url,null,null,null);

    }

    internal void Destroy()
    {
        try
        {
            if (browser.Parent != null)
            {
                ((Grid)browser.Parent).Children.Remove(browser);
                browser.Navigate("about:blank");
                browser.Dispose();
                browser = null;
            }
        }
        catch { }

    }

}


Here's how I did it:

// Needed to expose the WebBrowser's underlying ActiveX control for zoom functionality
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
internal interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.IUnknown)]
object QueryService(ref Guid guidService, ref Guid riid);
}
static readonly Guid SID_SWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");

private void ZoomListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
object zoomPercent; // A VT_I4 percentage ranging from 10% to 1000%
switch(ZoomListBox.SelectedItem.ToString())
{
    case "System.Windows.Controls.ListBoxItem: 200%":
        zoomPercent = 200;
        break;
    case "System.Windows.Controls.ListBoxItem: 100%":
        zoomPercent = 100;
        break;
    case "System.Windows.Controls.ListBoxItem: 50%":
        zoomPercent = 50;
        break;
    default:
        zoomPercent = 100;
        break;
}

// grab a handle to the underlying ActiveX object
IServiceProvider serviceProvider = null;
if (m_webView.Document != null)
{
    serviceProvider = (IServiceProvider)m_webView.Document;
}
Guid serviceGuid = SID_SWebBrowserApp;
Guid iid = typeof(SHDocVw.IWebBrowser2).GUID;
SHDocVw.IWebBrowser2 browserInst = (SHDocVw.IWebBrowser2)serviceProvider.QueryService(ref serviceGuid, ref iid);

// send the zoom command to the ActiveX object
browserInst.ExecWB(SHDocVw.OLECMDID.OLECMDID_OPTICAL_ZOOM, SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, ref zoomPercent, IntPtr.Zero);
}

All the service provider stuff exposes the ActiveX since the WPF WebBrowser control doesn't expose it directly. Aside from that, it's pretty much the same as alexei's solution.


This is not an exact answer since it is for the WinForms control, but perhaps will be useful in case you decide to use it in a WindowsFormsHost instead of the WPF control, which exposes way too little to be useful.

You could use an OLE commands through ExecWB on the ActiveX instance: OLECMDID_ZOOM for text size and OLECMDID_OPTICAL_ZOOM for optical zoom. For example,

object pvaIn = 200; // A VT_I4 percentage ranging from 10% to 1000%
var browserInst = ((SHDocVw.IWebBrowser2)(browserContol.ActiveXInstance));
browserInst.ExecWB(SHDocVw.OLECMDID.OLECMDID_OPTICAL_ZOOM,
                   SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER,
                   ref pvaIn, IntPtr.Zero);

Some notes:

  • a reference to Interop.SHDocVw assembly is needed
  • the command succeeds only after a document has loaded
  • the range of pvaIn could be retrieved via OLECMDID_GETZOOMRANGE
  • for reference list of commands is on MSDN
  • I experienced this strange behavior that seemed to happen only on non-96 dpi. Upon startup, the rendered text size did not correspond to that stored in OLECMDID_ZOOM state. Setting the value (to any value) did not fix the discrepancy: the rendered size is still what looked like [stored size + 2]. When optical zoom was set to 100%, the discrepancy in text-size went away (text size visibly shrank after zooming to 100%). This did't happen in IE, and perhaps that was just a weird artifact in my environment -- but just fyi.


When using the other solutions, I always get errors of kind

HRESULT: 0x80040100
DRAGDROP_E_NOTREGISTERED

I found a solution on this page that worked for me:

var wb = webBrowser.ActiveXInstance.GetType();

object o = zoomPercentage; // Between 10 and 1000.

wb.InvokeMember(
    @"ExecWB", 
    BindingFlags.InvokeMethod, 
    null, 
    webBrowser.ActiveXInstance, 
    new[]
        {
            OLECMDID.OLECMDID_OPTICAL_ZOOM, 
            OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, 
            o, 
            o
        }); 

With OLECMDID_OPTICAL_ZOOM being 63 and OLECMDEXECOPT_DONTPROMPTUSER being 2.

0

精彩评论

暂无评论...
验证码 换一张
取 消