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.
Related
I have a C# WPF application that is software captured using Open Broadcaster Software. When the application is in the foreground or even hidden by another application, it works just fine. However, if it is actually minimized, it stps updating. This makes sense, because usually, why would you need to redraw it if nobody can see it, but this is not true for this case. Is it possible to somehow force the UI to redraw? It would be possible to call a certain method every time a UI update is needed, because the code where I would need the UI to update/redraw looks something like this (simplified):
private void displaySomething(int something)
{
someRectangle.Fill = new SolidColorBrush(...);
// Redraw UI here
}
EDIT: "Update" might have been a misleading term here. "Redraw" may be better.
So if it works even the form is behind the other form, then do not let user to Minimize the form. Set yourWindow.ResizeMode = ResizeMode.NoResize;
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
I've tried all the answers suggest in Stack Overflow to get my scrollbar to move to the bottom as text is being updated, but I have a feeling its not working because it's within a thread. My code is below ...
foreach(HtmlAgilityPack.HtmlNode paginationUser in paginationUsers) {
String userUrl = paginationUser.GetAttributeValue("id","");
this.Invoke((MethodInvoker)delegate {
txtLog.AppendText("...... Added " + userUrl + Environment.NewLine);
txtLog.Select(txtLog.Text.Length, 0);
txtLog.ScrollToCaret();
});
}
Is it the thread thats causing the code not to work? And what's a better solution?
Try to add this code :
TextBox.SelectionStart = txtLogEntries.Text.Length;
TextBox.ScrollToCaret();
at onTextChanged TextBox event .
I feel using this code is better:
TextBox.AppendText("your text")
it will automatically scroll to the end of the newly appended text & the auto scrolling animation seems more smoother compared to TextBox.ScrollToCaret() method
you can put this code at TextChanged TextBox event
I am having the same problem with WPF, using a thread to write to the textbox. It works fine until I add the ScrollToEnd.
I have no solution, just some remarks.
You are not locking the control. You should if you are filling it from a tread.
If I use Invoke it does work (but the UI becomes unresponsive). I use BeginInvoke, which is smoother but then it totally locks up if I use ScrollToEnd.
It seems to be some kind of triggering issue, one event causing the other.
Try feeding text slowly and see what happens, the worker thread may be flooding the textbox, giving it a really hard time, not allowing the main thread to do its thing.
So I've got some serious problems with removing a Control from a Form of my application. It's kinda messed up but I can't change anything. I have a form and I have a separated user Control. The control opens an exe file and shows a progress bar while loading it's bytes. And here comes the problem. I do all of it with a BackgroundWorker and when the worker_DoWorkerCompleted method is called the original form should show a MessageBox and remove the Control.
BackGround_Loader bgLoad = new BackGround_Loader();
bgLoad.Location = new Point(this.Width/2 - bgLoad.Width/2, this.Height/2 - bgLoad.Height/2);
this.Controls.Add(bgLoad);
bgLoad.BringToFront();
bgLoad.AddReferences(this.executableFile, this.SourceReader);
bgLoad.occuredEvent();
At first I set the control's location to be in the middle of the Form itself. Then I add the control to the form, and bring it to the front. After these I send the path of the executable and a RichTextBox's reference to this. With the occuredEvent I start the BackgroundWorker itself. And here comes my problem. I should show a MessageBox in the Form when the in the bgLoad the backgroundworker gets to the DoWorkerCompleted status. Kindly I have no idea how to do it. It works just perfect however the control stays in the middle of the form.
UI actions must be performed on the main UI thread. The events that get raised from the background worker thread are (obviously) in a different thread.
You need something like the following code:
private void backgroundWorker_DoWork(object sender, AlbumInfoEventArgs e)
{
// Check with an element on the form whether this is a cross thread call
if (dataGridView.InvokeRequired)
{
dataGridView.Invoke((MethodInvoker)delegate { AddToGrid(e.AlbumInfo); });
}
else
{
AddToGrid(e.AlbumInfo);
}
}
In this case AddToGrid is my method for adding a row to a DataGridView, but in your case it will be a method that does what you need to do.
Similarly for the backgroundWorker_RunWorkerCompleted method
See this MSDN example
I could find a way to solve the problem but I don't really like it. In the addReferences method I pass the Form itself and an object of the bgLoad class. Then in the RunWorkerCompleted I check if the control is on the form and if it is then I remove it.
bgLoad.AddReferences(this, bgLoad, this.executableFile, this.SourceReader);
...
private void worker_DoWorkerCompleted(object sender, DoWorkerEventArgs e) {
if(this.MainForm.Controls.Contains(this.Control) {
this.MainForm.Controls.Remove(this.Control);
}
}
Like this it works but it's awful for me.
How can I create a Popup balloon like you would see from Windows Messenger or AVG or Norton or whomever?
I want it to show the information, and then slide away after a few seconds.
Edit: It needs to be blocking like Form.ShowDialog() because the program exits after displaying the notification
You can use the notifyIcon control that's part of .NET 2.0 System.Windows.Forms. That allows you to place an icon for your application in the System Tray. Then, you can call the ShowBalloonTip(int timeOut) method on that. Be sure however to first set the text, and icon properties on the notifyIcon for it to work. Small code sample:
private void button1_Click(object sender, EventArgs e)
{
this.notifyIcon1.BalloonTipText = "Whatever";
this.notifyIcon1.BalloonTipTitle = "Title";
this.notifyIcon1.Icon = new Icon("icon.ico");
this.notifyIcon1.Visible = true;
this.notifyIcon1.ShowBalloonTip(3);
}
EDIT: Ok, so notifyIcon won't work for you. My second suggestion would then be to create your own control for this. Actually, I would use a form. A simple form, with no borders, and no control box and just have a timer running so you can set the Opacity for fade in/out. Then, you can easily get the bottom right of the screen using the Rectangle Screen.PrimaryScreen.WorkingArea. Then just show your form at that position.
Don't create a modal (blocking) balloon. Please. A big part of the design of these UIs is that they are not dialogs: they're transient, potentially non-interactive elements, intended to provide incidental information to a user without necessarily interrupting their workflow. A balloon that steals focus and blocks user input would be irritating at best - if you need a dialog, then use a dialog.
The .NET 1.1 Visual Basic Power Pack had a toaster control.