I'm using webbrowser control in my winforms app (c#). And when it is doing automation things, I'm losing focus control from the window I was working with. Webbrowsers' form doesn't show up also, I just lose focus from the contol. I now writing this message I have to click into textbox again and again...
How to disable such behaviour in webbrowser?
I create invisible webbrowser like that:
var br = new WebBrowser();
br.Visible = false;
br.ScriptErrorsSuppressed = true;
Please advise.
I had the same problem:
The Webbrowser Control stole focus from the application once the URL is loaded.
This worked for me:
Before Webbrowser.Navigate() method call, set the parent control of the Webbrowser to Enabled = false.
At the DocumentCompleted event of the Webbrowser, reset parent control of the Webbrowser to Enabled = true.
You can't do it directly on Webbrowser because WebBrowserBase.Enabled is not supported.
Let me know if it works for you.
You could try disabling it globally via the SystemParametersInfo api. Use SPI_SETFOREGROUNDLOCKTIMEOUT. Setting foreground lockout is a global settings, so you will want to clear this setting when you're done. A more permanent solution is to change HKCU\Control Panel\Desktop\ForegroundLockTimeout registry key. See also this discussion on social.msdn (specifically, billb08's answer).
I guess WebBrowser acquires the focus after a page is loaded by calling Navigate (or the Click method of an HtmlElement, which causes navigation). The focus could be given back to the control on the window (the TextBox) in the DocumentComplete event handler of the WebBrowser, but this is very difficult:
When would you determine which control owned the focus
originally? Before calling Navigate? This is not enough, because the
user can move to another control after calling Navigate, but before
handling DocumentComplete.
AFAIK setting the focus to a TextBox will select its whole
content, so you will have to put the cursor back to its original
position. But when would you store the original position? Same problem.
There can be more than one DocumentComplete event after a single
Navigate (or Click).
A possible solution would be to create a separate application for your hidden WebBrowser. This second application would be invisible, and could communicate with the original GUI application using some InterProcess Communication (IPC) technique. Because the WebBrowser in this case would run in a different process, you would have a better chance not to lose lose the focus and bother the user.
it's a very complex problem to fix, and should be revised by microsoft, an app just stealing the focus is not logical, it does depend on what the website is doing though. I had to resort to a CBT filter, see http://msdn.microsoft.com/en-us/magazine/cc188966.aspx, and filter out unwanted HCBT_ACTIVATE and HCBT_SETFOCUS (return 1;). You can use GetWindowClass(wParam) to see what's going on.
Even above didn't entirely work, the app window would still pop to the front temporarily so worked around that using SetWindowPos HWND_TOPMOST and HWND_NOTOPMOST on the window currently in foreground. The HCBT_SETFOCUS gets hit 2 or 3 times so on 1st set HWND_TOPMOST and last set HWND_NOTOPMOST. Count how many classname == "Internet Explorer_Server" which should be 2 (or possibly depends on website?), the other is "Shell Embedding" but doesn't always occur. Hope it helps.
I was looking at all the other answers to this question and they weren't working for me, but i saw the one about settings Browser.Parent.Enabled = false; i tried so and got an error, so i tried this instead it just came to mind.
Browser.Parent = new Control();
Browser.Parent.Enabled = false;
And now the problem is completely gone, it does not take away focus anymore.
I am using the web browser class as a variable, it is not on my form.
well this worked for me try it, this seemed to be a 100% solution.
Most of the methods won't work for me on more than one web browser. This method is work with any amount of web browsers;
1. Put web browser into a panel and set panel enabled to false, then navigate;
webBrowser.Parent = panelBottom;
panelWebBrowser.Enabled = false;
webBrowser.Navigate("http://www.google.com");
2. Define a navigated event to web browser and delay panels enabling for a second;
private void webBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((obj) =>
{
panelWebBrowser.Enabled = true;
timer.Dispose();
},null, 1000, Timeout.Infinite);
}
My solution for sending the focus back to a form:
Private Sub Web_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles Web.DocumentCompleted
If Me.Visible = False Then
For Each f As Form In My.Application.OpenForms
If TypeOf f Is frmLogin Then
Dim fl As frmLogin = DirectCast(f, frmLogin)
If fl.Visible = True Then
fl.Focus()
Exit For
End If
End If
Next
End If
End Sub
Related
I'm making a program that has a Form with a ChromiumWebBrowser in it. The navigation is done automatically. When webbrowser complete it's task, I'll dispose it, create a new webbrowser, add it to form, and load a new address.
But, when the new webbrowser was created and added to form, the program jumps in front of what ever other program is in the top with focus. Example: I start my program, press the button to start its task, open notepad to type some text and my program jumps in front of it when navigating to a new site.
Even when the window is minimized, it still steals focus from other open programs.
How do I prevent it stealing focus after it is created?
As #amaitland said, this looks like a bug.
Workarounds I've used are:
1) disable the browser. This will prevent the browser from receiving mouse/keyboard input, but it won't "grey-out" the control.
Browser1 = New CefSharp.WinForms.ChromiumWebBrowser(url)
Browser1.Enabled = False
2) Pass a callback .net function for when the page loads where you simply put the focus back to winforms by focusing on a label of your choice.
Label1.Focus()
Your Form need set: this.Topmost = false;
AND just set: this.BringToFront();
Add new browser to the form just like the function as follow:
private ChromiumWebBrowser AddNewBrowser(FATabStripItem tabStrip, String url)
{
if (url == "")
{
url = OpenUrl;
txtUrl.Select();
txtUrl.Focus();
}
else
{
tabStrip.Select();
tabStrip.Focus();
}
// ...
}
Hope has help to you. Thanks !
I'm trying to put an icon in the system tray and then give it a global keyboard shortcut to carry out a function.
I'm using RegisterHotKey to set the global keyboard shortcut, and it works if the main form associated with the icon is visible. But if the form is invisible then the WndProc method is never invoked.
Any ideas?
Edit:
What I mean by "hidden" is that the following is added to the main form:
protected override void OnLoad(EventArgs e)
{
hotKey = new GlobalHotkey(GlobalHotkey.WIN, Keys.T, this);
bool registered = hotKey.Register();
Visible = false;
ShowInTaskbar = false;
base.OnLoad(e);
}
"registered" is showing as "true", and the shortcut key works fine if I leave out the "Visible = false;" and the "ShowInTaskbar = false;".
The problem is that setting ShowInTaskbar to false changes the window handle, which means that the hwnd passed to RegisterHotkey is no longer valid.
Registering the hotkey after setting ShowInTaskBar works fine.
Winforms works around a pretty draconian restriction in the winapi. Some properties of a window can only be specified when a window is created and can't be changed later. Or in other words, they are specified in the native CreateWindowEx() call.
It works around it by calling CreateWindowEx() again. Or in other words, destroy the existing window and create it again. That's a nifty trick but it does have some side effects. You can see a wee bit of flicker for example when the new window paints itself. Some bigger side effects are visible on for example a TreeView. All the nodes collapse when it gets recreated. Hard to avoid, there is just too much state associated with the original window. For a Form, the ShowInTaskbar property is one such property. But also RightToLeft, FormBorderStyle, ControlBox, etcetera.
The most relevant side-effect is the one you are running into. Recreating the window always changes the Handle property, inevitably. And that goes wrong when you use RegisterHotKey(), or a library that uses it, that winapi call uses the window handle. So when Winforms destroys that window there will never again be a callback.
It is easy to fix, you are just using the wrong event handler. Make the call in an override for the OnHandleCreated method instead. It re-runs when the window gets re-created. Yet another easy fix, but not nearly as reliable, is to only set properties like ShowInTaskbar in the constructor.
I have a button that launches a time intensive process. When the user hovers over this button a tool-tip is displayed, which is good. However, before this process gets re-routed onto a background thread (10 seconds or so for some stuff to take place) the tool-tip is displayed semi-transparent. I know this is awful coding and it should be put on to a non-UI thread ASAP, but this is the way it is for now...
My question is, how can I get a reference to the buttons tool-tip object so I can make it not visible? I envisage it to look like:
ToolTip someTT = Button.ToolTip; // This only gets or set the tool tip text.
someTT.Active = false;
someTT.Dispose(); // As a last resort.
Sorry guys, I aknowledge that I am a disgusting person for doing this.
Edit: The button is of the ComponantOne RibbonButton-type as part of the Studio for WinForms.
Usually, when you working with the ToolTip, you can find the following code within the Form.InitializeComponent() method:
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.button1 = new System.Windows.Forms.Button();
//...
this.toolTip1.SetToolTip(this.button1, "Tooltip for button1");
Thus you can disable tooltip for the specific button using the same approach:
this.toolTip1.SetToolTip(this.button1, null);
You can also disable a button when the background thread have been started. This also avoids unnecessary the tooltips above this button:
void button1_Click(object sender, EventArgs e) {
toolTip1.Hide(button1);
button1.Enabled = false;
//start the background thread here
}
You have to work with the ToolTip control that you added to your project. Something like ToolTip.Active might work.
From above link:
With the Active property, you can enable or disable the display of
ToolTip text for all controls that have text specified by this
particular ToolTip component. Although more than one ToolTip component
can be created and assigned to a form, setting the Active property to
false only affects the current ToolTip.
If the UI thread is doing work then it won't matter if you find a way to hide the tool tip, it still won't take place until the UI thread is freed up again.
Your solution is what you always knew it would be, move the non-UI processing to a non-UI thread.
I am using the Business Silverlight application. I have incorporated some MVVM into this and were off an running with it. We are using some telerik controls, mostly the ribbon control and the docking. We register all the telerik ribbon controls in the about.xaml.cs file, the method is DisplayUI - its here where we register the docking control then we register the ribbon after this. What happens is that when you click the ABOUT link it shows our first tab with buttons(perfect). when you click the HOME link next to the ABOUT link, we go back to the home page..but when you click the ABOUT link again it registers the controls again so we end up with two tabs that are the same.
Is there a way to check to see if this about.xaml.cs file has already been initialized? Im guessing that is has a handle on the first call in memory as I am able to see the first tabs rendering..
Thanks
here is the about code
public About()
{
InitializeComponent();
DisplayUI();
this.Title = ApplicationStrings.AboutPageTitle;
}
that display UI does all the work in registering the dockpanel and the ribbons. We'd like to not have the DisplayUI() called if this has already been rendered once.
If you do it by event handler can you unsubscribe from the event at the end of the method? Without seeing some code it's hard to work out what to change.
It's not the nicest way of doing it, but if this code needs to run once and only once then you could have a static boolean variable on the class set to false and when you call DisplayUI you check the value of this. If it's false you set it to true and run the method, and if it's true you just return.
I'm working on a C#.Net application which has a somewhat annoying bug in it. The main window has a number of tabs, each of which has a grid on it. When switching from one tab to another, or selecting a different row in a grid, it does some background processing, and during this the menu flickers as it's redrawn (File, Help, etc menu items as well as window icon and title).
I tried disabling the redraw on the window while switching tabs/rows (WM_SETREDRAW message) at first. In one case, it works perfectly. In the other, it solves the immediate bug (title/menu flicker), but between disabling the redraw and enabling it again, the window is "transparent" to mouse clicks - there's a small window (<1 sec) in which I can click and it will, say, highlight an icon on my desktop, as if the app wasn't there at all. If I have something else running in the background (Firefox, say) it will actually get focus when clicked (and draw part of the browser, say the address bar.)
Here's code I added.
m = new Message();
m.HWnd = System.Windows.Forms.Application.OpenForms[0].Handle; //top level
m.WParam = (IntPtr)0; //disable redraw
m.LParam = (IntPtr)0; //unused
m.Msg = 11; //wm_setredraw
WndProc(ref m);
<snip> - Application ignores clicks while in this section (in one case)
m = new Message();
m.HWnd = System.Windows.Forms.Application.OpenForms[0].Handle; //top level
m.WParam = (IntPtr)1; //enable
m.LParam = (IntPtr)0; //unused
m.Msg = 11; //wm_setredraw
WndProc(ref m);
System.Windows.Forms.Application.OpenForms[0].Refresh();
Does anyone know if a) there's a way to fix the transparent-application problem here, or b) if I'm doing it wrong in the first place and this should be fixed some other way?
There are calls on classes derived from Control for this purpose. They are SuspendLayout and PerformLayout. As they are on Control and Form is derived from Control, your Form has them too.
These calls suffice for most updates but in other circumstances, just hiding the control using Visible = false can be enough. To stop the flicker during this hiding and then reshowing of the control, I usually draw the control to a bitmap which I show in a PictureBox during the update. This is useful when updating trees, tab controls, or lists (as can turning off sorting during the update in that last example).
The behavior you're describing is not normal for a .NET winforms application. The fact that you're using WndProc and sending messages in your example suggests that there is a lot of other unusual stuff going on with this form (I'm guessing there's more than one thread involved). Another possibility that is common in tabbed interfaces is that your form is simply overloaded with controls; sometimes this can cause strange behavior.
I have never witnessed or heard of anything remotely like what you describe.
You can try override the Paint method on your control that you do not want rendered and control it by some global boolean (=ignore all painting while some bool is true.)
If your control is a 3rd party, subclass it and override it there.
Then when you are satisified, set the bool to false and let the control be painted again (might have to force a paint when you turn it on again with .Refresh?)
If this is a custom control, you can try some of the control style flags: I think DoubleBuffered or AllPaintingInWmPaint might help. You can change the style bits using Control.SetStyle (which is protected, which is why you need to do it in your own custom Control class).