Adding System.Windows.Forms.WebBrowser to System.Windows.Controls.StackPanel cannot convert to System.Windows.UIElement

1

I need to add WebBrowser control to dynamically generated Window in WPF application.

Basically when agent clicks on the link I need to open the webbrowser window that has close (X) button disabled (or hidden) on some pages and not on others. Reason is they get redirected to 3rd party payment system that collects the payment and if they close browser window after collecting the payment but before they are redirected back to our system we do not get notification of payment being collected while 3rd party charges our customers.

Originally web browser window was opened in Windows.Form, but I was unable to find a way to disable X on Form, so figured to switch to WPF Window since our app is WPF in the first place, so I introduced window and panel but now when dynamically adding WebBrowser control to panel Children it gives following error

Error cannot convert from 'Desktop.ViewModels.PaymentViewModel.NavigateToTakePaymentCommand.MyWebBrowser' to 'System.Windows.UIElement'

private void OpenBrowser(PaymentViewModel viewModel, Uri uri)
{
   viewModel.BrowserWindow = new WithoutCloseButton();
   viewModel.BrowserWindow.Closed += BrowserWindow_Closed;
   var browser = new MyWebBrowser();
   var stackPanel = new StackPanel { Orientation = System.Windows.Controls.Orientation.Vertical };
  stackPanel.Children.Add(browser); // this bit fails
  viewModel.BrowserWindow.Content = stackPanel;

...

public class WithoutCloseButton : Window
{
    private const int GWL_STYLE = -16;
    private const int WS_SYSMENU = 0x80000;
    [DllImport("user32.dll", SetLastError = true)]
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    [DllImport("user32.dll")]
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
}

public class MyWebBrowser : System.Windows.Forms.WebBrowser
{
    public static Guid IID_IHttpSecurity
        = new Guid("79eac9d7-bafa-11ce-8c82-00aa004ba90b");
    public static Guid IID_IWindowForBindingUI
        = new Guid("79eac9d5-bafa-11ce-8c82-00aa004ba90b");
    public const int S_OK = 0;
    public const int S_FALSE = 1;
    public const int E_NOINTERFACE = unchecked((int)0x80004002);
    public const int RPC_E_RETRY = unchecked((int)0x80010109);
    protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
    {
        return new MyWebBrowserSite(this);
    }

    class MyWebBrowserSite : WebBrowserSite, UCOMIServiceProvider,IHttpSecurity, IWindowForBindingUI
    {
        private MyWebBrowser myWebBrowser;
        public MyWebBrowserSite(MyWebBrowser myWebBrowser) : base(myWebBrowser)
        {
            this.myWebBrowser = myWebBrowser;
        }

        public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
        {
            if (riid == IID_IHttpSecurity)
            {
                ppvObject = Marshal.GetComInterfaceForObject(this
                    , typeof(IHttpSecurity));
                return S_OK;
            }
            if (riid == IID_IWindowForBindingUI)
            {
                ppvObject = Marshal.GetComInterfaceForObject(this
                    , typeof(IWindowForBindingUI));
                return S_OK;
            }
            ppvObject = IntPtr.Zero;
            return E_NOINTERFACE;
        }

        public int GetWindow(ref Guid rguidReason , ref IntPtr phwnd)
        {
            if (rguidReason == IID_IHttpSecurity || rguidReason == IID_IWindowForBindingUI)
            {
                phwnd = myWebBrowser.Handle;
                return S_OK;
            }
            else
            {
                phwnd = IntPtr.Zero;
                return S_FALSE;
            }
        }

        public int OnSecurityProblem(uint dwProblem)
        {
            //ignore errors
            //undocumented return code, does not work on IE6
            return S_OK;
        }
    }
}

How to add System.Windows.Forms.WebBrowser to System.Windows.Controls.StackPanel? Is there like a wrapper on something?

c#
wpf
winforms
webbrowser-control
uielement
asked on Stack Overflow Apr 18, 2016 by Matas Vaitkevicius • edited Oct 11, 2016 by P. Frank

2 Answers

0

To add Window Form controls in WPF you need WindowsFormsHost first. Add WindowsFormHost to your StackPanel and then add your webbrowser to WindowsFormHost. XAML examples are below:

1.

    <WindowsFormsHost>
        <wf:MaskedTextBox x:Name="mtbDate" Mask="00/00/0000"/>
    </WindowsFormsHost>

2.

   <wfh:WindowsFormsHost Grid.Row="1"  x:Name="wbFormHost" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" TabIndex="6">
        <wf:WebBrowser x:Name="webBrowser" x:FieldModifier="public" Dock="Fill"/>
    </wfh:WindowsFormsHost>

where wfh is xmlns:wfh="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"

answered on Stack Overflow Apr 18, 2016 by Kylo Ren
0

With help from @Siderite Zackwehdex

I had to add reference to WindowsFormsIntegration. Go to project and expand References -> Add Reference -> Assemblies -> Framework -> tick WindowsFormsIntegration.

enter image description here

Then I had to change the following bits.

public class WithoutCloseButton : Window
        {
            private const int GWL_STYLE = -16;
            private const int WS_SYSMENU = 0x80000;

            [DllImport("user32.dll", SetLastError = true)]
            private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
            [DllImport("user32.dll")]
            private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

//THIS IS NEW
            public void HideButtons()
            {
                var hwnd = new WindowInteropHelper(this).Handle;
                SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
            }
        }

and then in OpenBrowser() I had to wrap WebBrowser in WindowsFormsHost

 private void OpenBrowser(PaymentViewModel viewModel, Uri uri)
 {
    viewModel.BrowserWindow = new WithoutCloseButton();
    viewModel.BrowserWindow.Closed += BrowserWindow_Closed;
    var browser = new MyWebBrowser();
    var stackPanel = new StackPanel { Orientation = System.Windows.Controls.Orientation.Vertical };
    var formsHost = new WindowsFormsHost {Child = browser};
    stackPanel.Children.Add(formsHost);
    viewModel.BrowserWindow.Content = stackPanel;
//....    then            
 browser.Navigate("about:blank");
 browser.DocumentCompleted += delegate(object obj, WebBrowserDocumentCompletedEventArgs e)
{
    if (e.Url.ToString() == "about:blank")
    {
        ((MyWebBrowser)obj).Navigate(uri);
    }

    if (e.Url.ToString().ToLower().Contains("accepted"))
    {
        ViewModel.AuthCode = this.GetAuthToken();
        ViewModel.updateUiWhenDoneWithPayment_RunWorkerCompleted(new object(), null);
        ViewModel.BrowserWindow.Close();
        ViewModel.BrowserWindow = null;
    }
    //THIS IS NEW
    if (e.Url.ToString().ToLower().Contains("payment/confirmation"))
    {
        viewModel.BrowserWindow.HideButtons();
    }
};
answered on Stack Overflow Apr 18, 2016 by Matas Vaitkevicius • edited Apr 19, 2016 by Matas Vaitkevicius

User contributions licensed under CC BY-SA 3.0