Scrolling problem with a WebBrowser control contained in a Panel control - c#

I have a .Net Panel control that contains a single child control that is a WebBrowser. I won't go into the reasons for me doing that, but it is related to printing out the control. The panel control has its AutoScroll property set to "true" and I am sizing the WebBrowser to fit its own content (by using the .Document.Body.ScrollRectangle.Size property of the WebBrowser when the NavigateComplete2 event fires). In this way, the scrollbar on the panel appears and you can scroll the panel up and down in order to be able to see the content of the WebBrowser.
The problem is that when you scroll down to see what's at the bottom of the WebBrowser and then click on it (perhaps you click on a link in the html), the panel jumps back to the top and the link doesn't get actioned.
Please can anyone help me to understand what's going on and how to get around this problem?

I had the same problem, also with a WebBrowser inside a Panel. Here's the solution I'm using (which I found somewhere else on stackoverflow):
class AutoScrollPanel : Panel
{
public AutoScrollPanel()
{
Enter += PanelNoScrollOnFocus_Enter;
Leave += PanelNoScrollOnFocus_Leave;
}
private System.Drawing.Point scrollLocation;
void PanelNoScrollOnFocus_Enter(object sender, System.EventArgs e)
{
// Set the scroll location back when the control regains focus.
HorizontalScroll.Value = scrollLocation.X;
VerticalScroll.Value = scrollLocation.Y;
}
void PanelNoScrollOnFocus_Leave(object sender, System.EventArgs e)
{
// Remember the scroll location when the control loses focus.
scrollLocation.X = HorizontalScroll.Value;
scrollLocation.Y = VerticalScroll.Value;
}
protected override System.Drawing.Point ScrollToControl(Control activeControl)
{
// When the user clicks on the webbrowser, .NET tries to scroll to
// the control. Since it's the only control in the panel it will
// scroll up. This little hack prevents that.
return DisplayRectangle.Location;
}
}

try setting TabStop to false on both the containing panel as well as the WebBrowser control. That did the trick for me. The reason this works is that if it's set as a wanting to be a tabstop, it will take the first click event to mean that it's receiving focus. This then resets the scroll bar positions... not sure why it does that...
However, on navigating to a new page you'll need to manually reset the scroll bar positions...
Here is what I used. Yeah it's a hack.
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
webBrowser1.TabStop = true;
webBrowser1.Focus();
webBrowser1.TabStop = false;
}

Related

Changing visiblity screwing up events in C#?

I have setup a Panel that has a number of Buttons on it. These Buttons Visible Property is set to false. When I move the mouse over the Panel they became Visible and when I move the mouse out of the Panel they once again became invisible. This all works fine.
The code to do this is:
private void _Display_MouseEnter(object sender, EventArgs e)
{
foreach (Control C in _Display.Controls)
{
C.Visible = true;
}
}
private void _Display_MouseLeave(object sender, EventArgs e)
{
foreach (Control C in _Display.Controls)
{
C.Visible = false;
}
}
The problem is the Events I have set for the Buttons seem to get removed by doing this. If I don't change the Buttons visiblity the events fire as normal. I have set the events in the Designer.
Am I missing something or is this how its supposed to work and I have to resubscribe my events each time I change the Buttons visiblity?
Thanks
Danny
I did some research on that and apparently when the cursor enters one of the buttons the Panel's MouseEnter and MouseLeave events fire until the cursor leaves that button so what it does is not allowing your buttons to catch the Click event.
I think the best solution would be to get the cursor position and check if it is within your panel and then set your buttons visibility.

ToolStripButton "Reset Appearance" / "Fire Leave Event"

I have a ToolStripButton that performs an action. The user clicks the button and the button is disabled to prevent the action being performed twice. After the action is complete the button is re-enabled. It all works perfectly...except:
Because the button is disabled it does not fire the "MouseLeave" event and as a result the appearance of the button is not updated. To be absolutely clear, when the mouse enters a ToolStripButton the button is highlighted in orange (by default) with a black box around it. This highlight is not being removed when I re-enable the button. The mouse cursor is, by this time, long gone from the control. Mousing over the button naturally fixes the button by redrawing it.
What I would like to do would be some method on the ToolStripButton that "resets" its appearance. Such a method may even exist on the ToolStrip, but despite searching I have been unable to find anything like this.
As an alternative I could fire the "Mouse Leave" event on the button directly. As far as I know there is no way to easily do this in C# .NET.
Any advice at this point in time would be most appreciated, naturally I don't want to tear up my application and replace the tool strip.
Update:
I reproduced your problem, trying figuring out!
I didn't get a better way other than reset the style in the click event
private void toolStripButton1_Click(object sender, EventArgs e)
{
toolStripButton1.BackColor = Color.FromKnownColor(KnownColor.Control);
toolStripButton1.Enabled = false;
}
private void toolStripButton1_MouseEnter(object sender, EventArgs e)
{
toolStripButton1.BackColor = Color.Red;
}
private void toolStripButton1_MouseLeave(object sender, EventArgs e)
{
toolStripButton1.BackColor = Color.FromKnownColor(KnownColor.Control);
}
Hope this helps!
Have you tried Control.Invalidate()?
from MSDN: Invalidates the entire surface of the control and causes the control to be redrawn.
I had the same problem. I "fixed" it by hiding and then showing back the ToolStripButton using the Visible property after the task was complete.
Before disabling ToolStrip or ToolStripItem:
private void RemoveHighlightFromToolStrip(ToolStrip toolStrip)
{
foreach (ToolStripItem item in toolStrip.Items)
{
if (item.Pressed || item.Selected)
{
item.Visible = false;
item.Visible = true;
}
}
}
also you can just hide and show entire ToolStrip, but this may affect other controls in your form (i.e. if you have some docked DataGridView it would be redrawn)

Is there any way to detect a mouseclick outside a user control?

I'm creating a custom dropdown box, and I want to register when the mouse is clicked outside the dropdown box, in order to hide it. Is it possible to detect a click outside a control? or should I make some mechanism on the containing form and check for mouseclick when any dropdownbox is open?
So I finally understand that you only want it to close when the user clicks outside of it. In that case, the Leave event should work just fine... For some reason, I got the impression you wanted it to close whenever they moved the mouse outside of your custom dropdown. The Leave event is raised whenever your control loses the focus, and if the user clicks on something else, it will certainly lose focus as the thing they clicked on gains the focus.
The documentation also says that this event cascades up and down the control chain as necessary:
The Enter and Leave events are hierarchical and will cascade up and down the parent chain until the appropriate control is reached. For example, assume you have a Form with two GroupBox controls, and each GroupBox control has one TextBox control. When the caret is moved from one TextBox to the other, the Leave event is raised for the TextBox and GroupBox, and the Enter event is raised for the other GroupBox and TextBox.
Overriding your UserControl's OnLeave method is the best way to handle this:
protected override void OnLeave(EventArgs e)
{
// Call the base class
base.OnLeave(e);
// When this control loses the focus, close it
this.Hide();
}
And then for testing purposes, I created a form that shows the drop-down UserControl on command:
public partial class Form1 : Form
{
private UserControl1 customDropDown;
public Form1()
{
InitializeComponent();
// Create the user control
customDropDown = new UserControl1();
// Add it to the form's Controls collection
Controls.Add(customDropDown);
customDropDown.Hide();
}
private void button1_Click(object sender, EventArgs e)
{
// Display the user control
customDropDown.Show();
customDropDown.BringToFront(); // display in front of other controls
customDropDown.Select(); // make sure it gets the focus
}
}
Everything works perfectly with the above code, except for one thing: if the user clicks on a blank area of the form, the UserControl doesn't close. Hmm, why not? Well, because the form itself doesn't want the focus. Only controls can get the focus, and we didn't click on a control. And because nothing else stole the focus, the Leave event never got raised, meaning that the UserControl didn't know it was supposed to close itself.
If you need the UserControl to close itself when the user clicks on a blank area in the form, you need some special case handling for that. Since you say that you're only concerned about clicks, you can just handle the Click event for the form, and set the focus to a different control:
protected override void OnClick(EventArgs e)
{
// Call the base class
base.OnClick(e);
// See if our custom drop-down is visible
if (customDropDown.Visible)
{
// Set the focus to a different control on the form,
// which will force the drop-down to close
this.SelectNextControl(customDropDown, true, true, true, true);
}
}
Yes, this last part feels like a hack. The better solution, as others have mentioned, is to use the SetCapture function to instruct Windows to capture the mouse over your UserControl's window. The control's Capture property provides an even simpler way to do the same thing.
Technically, you'll need to p/invoke SetCapture() in order to receive click events that happen outside of your control.
But in your case, handling the Leave event, as #Martin suggests, should be sufficient.
EDIT: While looking for an usage example for SetCapture(), I came across the Control.Capture property, of which I was not aware. Using that property means you won't have to p/invoke anything, which is always a good thing in my book.
So, you'll have to set Capture to true when showing the dropdown, then determine if the mouse pointer lies inside the control in your click event handler and, if it doesn't, set Capture to false and close the dropdown.
UPDATE:
You can also use the Control.Focused property to determine if the control has got or lost focus when using a keyboard or mouse instead of using the Capture with the same example provided in the MSDN Capture page.
Handle the Form's MouseDown event, or override the Form's OnMouseDown
method:
enter code here
And then:
protected override void OnMouseDown(MouseEventArgs e)
{
if (!theListBox.Bounds.Contains(e.Location))
{
theListBox.Visible = false;
}
}
The Contains method old System.Drawing.Rectangle can be used to indicate if
a point is contained inside a rectangle. The Bounds property of a Control is
the outer Rectangle defined by the edges of the Control. The Location
property of the MouseEventArgs is the Point relative to the Control which
received the MouseDown event. The Bounds property of a Control in a Form is
relative to the Form.
You are probably looking for the leave event:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.leave.aspx
Leave occurs when the input focus leaves the control.
I just wanted to share this. It is probably not a good way of doing it that way, but looks like it works for drop down panel that closes on fake "MouseLeave", I tried to hide it on Panel MouseLeave but it does not work because moving from panel to button leaves the panel because the button is not the panel itself. Probably there is better way of doing this but I am sharing this because I used about 7 hours figuring out how to get it to work. Thanks to #FTheGodfather
But it works only if the mouse moves on the form. If there is a panel this will not work.
private void click_to_show_Panel_button_MouseDown(object sender, MouseEventArgs e)
{
item_panel1.Visible = true; //Menu Panel
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!item_panel1.Bounds.Contains(e.Location))
{
item_panel1.Visible = false; // Menu panel
}
}
I've done this myself, and this is how I did it.
When the drop down is opened, register a click event on the control's parent form:
this.Form.Click += new EventHandler(CloseDropDown);
But this only takes you half the way. You probably want your drop down to close also when the current window gets deactivated. The most reliable way of detecting this has for me been through a timer that checks which window is currently active:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
and
var timer = new Timer();
timer.Interval = 100;
timer.Tick += (sender, args) =>
{
IntPtr f = GetForegroundWindow();
if (this.Form == null || f != this.Form.Handle)
{
CloseDropDown();
}
};
You should of course only let the timer run when the drop down is visible. Also, there's probably a few other events on the parent form you'd want to register when the drop down is opened:
this.Form.LocationChanged += new EventHandler(CloseDropDown);
this.Form.SizeChanged += new EventHandler(CloseDropDown);
Just don't forget to unregister all these events in the CloseDropDown method :)
EDIT:
I forgot, you should also register the Leave event on you control to see if another control gets activated/clicked:
this.Leave += new EventHandler(CloseDropDown);
I think I've got it now, this should cover all bases. Let me know if I'm missing something.
If you have Form, you can simply use Deactivate event just like this :
protected override void OnDeactivate(EventArgs e)
{
this.Dispose();
}

Focusing WebBrowser control in a C# application

I have a WebBrowser control hosted in a windows Form. The control is used to display hyperlinks which get created at runtime. These links point to some HTML pages and PDF documents.
The problem is that when the form hosting the browser control is loaded, the focus is on the form. When the TAB key is pressed, the focus does not shift to the first hyperlink. However, if I perform a mouse click on the control and then hit the TAB key, the tab focus is now on the first hyper link. I tried using Select() on the WebBrowser control and then I called Focus(), but it doesn't solve the problem.
Any ideas on how to set the tab focus on the first hyperlink at load? Thanks.
Cheers,
Harish
I guess it might be because the focus is set before the page is fully loaded. Try this:
private void Go(string url)
{
webBrowser1.Navigate(url);
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
webBrowser1.Document.Body.Focus();
}
You could also automatically select the focus on the first link directly by getting the HtmlElement of that first link.
If the above doesn't work, you might want to check other parts of your code to see if anything else is capturing the focus. Try searching for Select, Focus and ActiveControl in your code.
Use form.ShowDialog(form) instead on form.Show(), then it will work !
where form is the running instance of your windows Form
This is my solution
private void txtAdres_KeyPress(object sender, KeyPressEventArgs e)
{
int licznik = 1;
if (e.KeyChar == (char)13)
{
string adres = txtAdres.Text;
webBrowser1.Navigate(adres);
licznik = 0;
}
if (licznik == 0)
{
webBrowser1.Focus();
}
}
In a normal scenario it should be sufficient for you to set the TabIndex of the WebBrowser control to zero. This way, when the form loads the control will be focused and pressing TAB will iterate through the links.
Note that you should also change the TabIndex of the other controls on the form.
If this does not solve your problem, you need to add more detail on the complexity of the form hosting the control.

Tooltip not displaying, flashes when control is clicked

I have a check box that is disabled that should be showing a tooltip when hovered over, but instead nothing happens. Once the checkbox is clicked on the tooltip shows momentarily then flashes on and off very fast. What could be causing this?
The tooltip should also be showing for every control involved, but shows for some and not others eventhough the tooltip is explicitly set for all controls. What could be causing this behavior?
Here is the event handler:
this.MouseHover += new EventHandler(OrderSummaryDetails_MouseHover);
void EventHandler_MouseHover(object sender, EventArgs e)
{
if (someCondition)
{
this.mFormTips.Show("Please open order form to manually modify this order", this);
}
}
I can't be positive, but if using WinForms, and you have your checkbox disabled (as in not enabled), then the checkbox will not receive events. This will cause tooltips not to show up properly.
I had the exact same problem before with a image button and what I ended up having to do was to create a gray scale of the image and swap it out when I wanted the button to be "disabled". I had to add the tooltip to the button and the image (two separate UI elements) and swap out the UI elements.
I added a MouseMove event and applied it to all the controls.
void OrderSummaryDetails_MouseMove(object sender, MouseEventArgs e)
{
Control control = GetChildAtPoint(e.Location);
if (control != null)
{
string toolTipString = mFormTips.GetToolTip(control);
this.mFormTips.ShowAlways = true;
// trigger the tooltip with no delay and some basic positioning just to give you an idea
mFormTips.Show(toolTipString, control, control.Width / 2, control.Height / 2);
}
}

Categories

Resources