Welcome Guest Search | Active Topics | Sign In | Register

Can't create again a WebView Options
Oscar
Posted: Thursday, November 12, 2015 1:35:20 PM
Rank: Member
Groups: Member

Joined: 11/12/2015
Posts: 10
Hi.

Due to the huge memory consumption of the component (or the Chrome engine), after an hour working my application consume all the available memory.
As I read in this forum the solution is to destroy the WebView and create again but when I try to do this the new WebView doesn't shows in the Form and doesn't works. After some hours I have two examples, one works and the other no, the problem is that I need the approach used in the one that doesn't works and I don't know what's going wrong with this example, so here we go with the code:

First a working example

Code: C#
public partial class Form1 : Form
    {
        #region Variables

        private WebView _browser;
        private IntPtr _handle;
        private bool _completed = false;

        #endregion

        public Form1(string instanceId)
        {
            InitializeComponent();

            EO.Base.Runtime.Exception += Runtime_Exception;
            _handle = Handle;
            CreateWebView();
        }

        public void DestroyView()
        {
            _browser.Dispose();
            _browser = null;
            Application.DoEvents();
            CreateWebView();
        }

        public void CreateWebView()
        {
            _browser = new WebView();

            _browser.LoadCompleted += _browser_LoadCompleted;
            _browser.ZoomFactor = 0.35;
            _browser.Url = "google.com";
            _browser.Create(_handle);
        }

        private void _browser_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            DestroyView();
            CreateWebView();
        }

        private void Runtime_Exception(object sender, ExceptionEventArgs e)
        {
            Console.WriteLine(e);
        }
    }


In this example I only load google.com and when the loadCompled event arrives I destroy the WebView and create a new one, as you can see very simple.

Now the example that doesn't works

Code: C#
public partial class Form1 : Form
    {
        #region Variables

        private WebView _browser;
        private IntPtr _handle;
        private bool _completed = false;

        #endregion

        public Form1(string instanceId)
        {
            InitializeComponent();

            _handle = Handle;
            CreateWebView();
            new Thread(() => foo()).Start();
        }

        public void foo()
        {
            while (true) {
                if (_completed) {
                    _completed = false;
                    Console.WriteLine("Creating the view again");
                    DestroyView();
                    CreateWebView();
                }
                Thread.Sleep(5000);
            }
        }

        public void DestroyView()
        {
            _browser.Dispose();
            _browser = null;
            Application.DoEvents();
            CreateWebView();
        }

        public void CreateWebView()
        {
            _browser = new WebView();
            EO.Base.Runtime.Exception += Runtime_Exception;

            _browser.LoadCompleted += _browser_LoadCompleted;
            _browser.ZoomFactor = 0.35;
            _browser.Url = "google.com";
            _browser.Create(_handle);
        }

        private void _browser_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            _completed = true;
        }

        private void Runtime_Exception(object sender, ExceptionEventArgs e)
        {
            Console.WriteLine(e);
        }
    }


In this case I create teh WebVIew in the same way but when loads set _complete = true, so the foo function must destroy the WebView and create another one, but in this case when the new WebView is created isn't visible and doesn't works.


Thanks in advance.
eo_support
Posted: Thursday, November 12, 2015 3:26:17 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,229
Hi,

This is a very common mistake. The root of the problem is you can NOT just create a WebView in any thread. The WebView relies on Windows messages to do a lot of internal work. So in order for a WebView to work, the thread that created the WebView must continue pumping messages throughout the WebView's whole life time. This is not an isue if you create WebView in your UI thread directly since your UI thread will pump messages until your application exits.

This is a problem if you try to create a WebView in a worker thread and your worker thread does not pump message. This is your case. So the new WebView will not function. We have a special class just for this purpose --- so that you can create WebView in a worker thread:

http://www.essentialobjects.com/doc/webbrowser/start/webview_no_ui.aspx

Even the above class allows you to create a WebView in a separate thread, you still should not mix up that WebView with your main UI. For example, you should not set _browser.WebView to the new WebView created by a different thread. Doing so would involes multiple threads in the same UI window tree (_browser is associated to your main UI thread and WebView is associated to a worker thread). Having multiple threads involved in the same UI tree is a dangerous area that you can run into all kind of issues (particularly deadlock issues) if you are not familar with that area. So generally it should be avoided unless you have a compelling reason to do so and you know exactly what you are doing.

Thanks
Oscar
Posted: Thursday, November 12, 2015 5:26:16 PM
Rank: Member
Groups: Member

Joined: 11/12/2015
Posts: 10
Hi again.

Thanks for your quick response, for your information I found a solution to this problem.
Here is the code.

Code: C#
public partial class TestForm : Form
    {
        #region Variables

        private WebView _browser;
        private IntPtr _handle;
        private bool _completed = false;

        #endregion

        public delegate void InvokeRestartDelegate();
        public void InvokeRestart()
        {
            if (InvokeRequired)
            {
                Invoke(new InvokeRestartDelegate(InvokeRestart));
            }
            else
            {
                Console.WriteLine("Creating the view again");
                DestroyView();
                CreateWebView();
            }
        }

        public TestForm()
        {
            InitializeComponent();

            _handle = Handle;
            CreateWebView();
            new Thread(() => foo()).Start();
        }

        public void foo()
        {
            while (true)
            {
                if (_completed)
                {
                    _completed = false;
                    InvokeRestart();
                }
                Thread.Sleep(5000);
            }
        }

        public void DestroyView()
        {
            _browser.Dispose();
            _browser = null;
            Application.DoEvents();
            CreateWebView();
        }

        public void CreateWebView()
        {
            _browser = new WebView();
            EO.Base.Runtime.Exception += Runtime_Exception;

            _browser.LoadCompleted += _browser_LoadCompleted;
            _browser.ZoomFactor = 0.35;
            _browser.Url = "google.com";
            _browser.Create(_handle);
        }

        private void _browser_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            _completed = true;
        }

        private void Runtime_Exception(object sender, ExceptionEventArgs e)
        {
            Console.WriteLine(e);
        }
    }

eo_support
Posted: Thursday, November 12, 2015 6:42:32 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,229
This will work. But why the first sample won't work for you? You don't need a separate thread just keep checking _completed when you know precisely when that variable turns true.
Oscar
Posted: Friday, November 13, 2015 3:36:48 AM
Rank: Member
Groups: Member

Joined: 11/12/2015
Posts: 10
These example was only this, simple examples, the point is that the kind of application I want to do is going to do some stuff and then wait until more work arrives, so think in the _finished variable as something that happens in other level (not the load complete) so a Thread must be running performing regular connections to the database and launching a WebView with several tasks when this tasks are created in the database.


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.