简体   繁体   中英

Disable editable WebBrowser control's save dialog C#

I hope you guys can help me out here.

I have an application written in C#, that uses a WebBrowser control to edit HTML files (marked with 2 on the screenshot), and here's the code that initializes it:

    htmlEditor.DocumentText = "";
    doc = htmlEditor.Document.DomDocument as IHTMLDocument2;
    doc.designMode = "On";
    htmlEditor.Url = new Uri(Properties.Main.Default.tempDir + "\\section-1.html");

I also have a listview control, that shows the list of HTML files(marked with 1 on the screenshot). Each time the user clicks on a list item, an event is triggered and the webbrowser control loads a different HTML file, and here's the code for that:

    private void sectionsTree_SelectedNodeChanged(object sender, RadTreeViewEventArgs e)
    {
        Sections.fileCheck();

        if (sectionsTree.SelectedNode != null)
        {
            emDataSet.dtSectionsDataTable sectionsDT = new emDataSet.dtSectionsDataTable();
            sectionsDT.ReadXml(Properties.Main.Default.tempDir + "\\sections.xml");

            for (int i = 0; i < sectionsDT.Rows.Count; i++)
            {
                if (sectionsTree.SelectedNode.Text == sectionsDT.Rows[i][2].ToString())
                {
                    htmlEditor.Url = new Uri(Properties.Main.Default.tempDir + "\\" + sectionsDT.Rows[i][1].ToString());
                }
            }
        }
    }

Now here comes my problem: because the HTML page loaded in the webbrowser control is editable, each time I select a new item on the list (and before a new HTML file is loaded) a Save dialog appears (marked with 3 on the screenshot). I have my own code to save the changed HTML file, triggered by the "changing" event and it would be great if there would be somehow a solution to bypass, suppress, skip, or just simply hide this Save dialog, so the user won't need to click it every time he wants to go to another file. Here's the changing event:

    private void sectionsTree_SelectedNodeChanging(object sender, RadTreeViewCancelEventArgs e)
    {
        Sections.fileCheck();

        if (sectionsTree.SelectedNode != null)
        {
            emDataSet.dtSectionsDataTable sectionsDT = new emDataSet.dtSectionsDataTable();
            sectionsDT.ReadXml(Properties.Main.Default.tempDir + "\\sections.xml");

            for (int i = 0; i < sectionsDT.Rows.Count; i++)
            {
                if (sectionsTree.SelectedNode.Text == sectionsDT.Rows[i][2].ToString())
                {
                    File.WriteAllText(Properties.Main.Default.tempDir + "\\" + sectionsDT.Rows[i][1].ToString(), htmlEditor.DocumentText);
                }
            }
        }
    }

My opinion is that the above codes are okay, and have nothing to do with my problem, because, my understanding is that the problem comes from a built-in feature of the WebBrowser control, however, just maybe, it could be a solution to intercept the WebBrowser control just before it checks if the file has been changed or not, and save it, so when it's checked it won't trigger the Save dialog, but I haven't figured out how to do that.

在此处输入图片说明

I'm looking forward to all your answers, and feel free to ask anything.

Thanks, Aemeth

you may use this

WebBrowser1.Document.ExecCommand(“Refresh”, False, “”)

found at this http://www.spheregen.com/disable-save-dialog-in-webbrowser-editing/

Hope to work for you

I've run into this recently and never had success using the Document.ExecCommand("Refresh") as described.

What has worked for me is to use Windows API calls to send the WM_CLOSE message to the dialog, allowing me to suppress the dialog but still handle the file saving/reloading in the background.

SO answer: Setting up Hook on Windows messages was helpful in setting everything up, but the general gist of it was to obtain the dialog class ( #32770 ), then make sure that the title of the dialog contained my temporary filename, then obtain the handle to that dialog and send it WM_CLOSE .

The body of my delegate function for SetWinEventHook is as follows, hopefully this is of some help.

GetClassName(hWnd, ClassName, ClassName.Capacity);
GetWindowText(hWnd, DialogTitle, DialogTitle.Capacity);
DialogHandle = FindWindow(DIALOG_CLASS, DialogTitle.ToString());

if (ClassName.ToString() == DIALOG_CLASS && DialogTitle.ToString().Contains(TempFilename))
{
     ReturnValue = SendMessage(DialogHandle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}

ClassName and DialogTitle are of StringBuilder type, ReturnValue and DialogHandle are of IntPtr type. TempFilename is a string containing a tempfile name generated by Path.GetTempFileName()

You'll need API calls to SetWinEventHook , UnhookWinEvent , GetClassName , GetWindowText , FindWindow , and SendMessage - PInvoke.net should be able to help with those. You'll also need a few constants setting up, again - PInvoke can help.

It's not the most elegant solution, but it works!

Edited to add - if you want to actually interact with the dialog, rather than just arbitrarily close it, you can use the code found at PInvoke here: http://www.pinvoke.net/default.aspx/user32.enumchildwindows then, pass DialogHandle in the code above to the GetChildWindows() function and iterate through the list of returned IntPtr objects, calling GetWindowText() on each item until you find a value that matches either " &Yes " (for the Yes button), " &No " (for the No button) or " Cancel " (for the cancel button).

Once you have the handle of the button, send it the BM_CLICK message (0x00F5) and you can suppress the dialog without losing the functionality of it.

As you're only iterating through the targeted dialog rather than every window, this is a pretty fast operation (took 2ms when tested) so shouldn't cause any slowdowns.

The code changes to the following:

GetClassName(hWnd, ClassName, ClassName.Capacity);
GetWindowText(hWnd, DialogTitle, DialogTitle.Capacity);
DialogHandle = FindWindow(DIALOG_CLASS, DialogTitle.ToString());

if (ClassName.ToString() == DIALOG_CLASS && DialogTitle.ToString().Contains(TempFilename))
{
    foreach (IntPtr ChildWindow in GetChildWindows(hWnd))
    {
        StringBuilder ChildCaption = new StringBuilder(100);
        GetWindowText(ChildWindow, ChildCaption, ChildCaption.Capacity);
        if (ChildCaption.ToString() == @"&Yes")
        {
            SendMessage(ChildWindow, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM