How can I tell if a control is being visualized? - winforms

Is there a property (in WinForms) that allows me to tell whether a specific control is being visualized on the screen (even if partially)? That is,
its Visible property is true, and
it is not covered by other windows.

This is no longer possible on Vista and up with Aero enabled. Windows are visible in for example window thumbnails and Aero Peek, even if they are overlapped by other windows. Rely on Windows asking for paints, don't try to optimize them. And use Invalidate() if you have a reason to repaint, never paint directly.

Check to see if the Paint event is firing is probably your best bet.
private void myControl_Paint(object sender, PaintEventArgs e)
{
this.Text = "Painted at " + DateTime.Now.ToString();
}

Related

General Question About WPF Control Behavior and using Invoke

I have been putting off activity on SO because my current reputation is "1337". :)
This is a question of "why" and not "how". By default, it seems that WPF does not set focus to the first control in a window when it's opening. In addition, when a textbox gets focus, by default it does not have it's existing text selected. So basically when I open a window, I want focus on the first control of the window, and if that control is a textbox, I want it's existing text (if any) to be selected.
I found some tips online to accomplish each of these behaviors, and combined them. The code below, which I placed in the constructor of my window, is what I came up with:
Loaded += (sender, e) =>
{
MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
var textBox = FocusManager.GetFocusedElement(this) as TextBox;
if (textBox != null)
{
Action select = textBox.SelectAll;
//for some reason this doesn't work without using invoke.
Dispatcher.Invoke(DispatcherPriority.Loaded, select);
}
};
So, my question. Why does the above not work without using Dispatcher.Invoke? Is something built into the behavior of the window (or textbox) cause the selected text to be de-selected post-loading?
Maybe related, maybe not--another example of where I had to use Dispatcher.Invoke to control the behavior of a form:
WPF Focus In Tab Control Content When New Tab is Created
All WPF controls have thread affinity. The Dispatcher manages the thread that each control was created on (typically this is a single thread for every control in the application, but not necessarily). Work is queued on this thread and executed in priority order.
Any UI-manipulating code has to be executed on the same thread as the control was created on - the Dispatcher thread - and so any method has to invoke back to that thread before it can do anything that would affect the UI (such as selecting text in the TextBox).
That said, it's my understanding that the Loaded eventhandler would fire on the Dispatcher thread by default, so I'm not entirely sure why you're seeing this behaviour in your specific example!
I should start by mentioning i had no issues making that work w/ out the dispatcher call in .net 4.0 (it may have been fixed in the framework update)- however, what the previous poster mentioned is accurate and has been the pardigm since the dawn of winforms (.DoActions() and .Invoke()). However, in 3.5 the above did work w/ out dispatcher if you use a method defined in the codebehind as the target call in your lambda:
Loaded += (sender, e) =>
{
this.SelectText();
};
void SelectText()
{
MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
var textBox = FocusManager.GetFocusedElement(this) as TextBox;
if (textBox != null)
{
textBox.SelectAll();
}
}
As to why, I cant really give you the specifics but I've run into similar issues w/ using lambdas to route events on presenters. I want to say its something to do w/ reference or context of the compiled expression- in this case it needs a ref to the containing object in order to know how to delegate the operation (selecting the textbox text on the right thread). I also believe that GC can occasionally clean up resources so deferred execution gets botched (seen it in F#...believed that was the cause of my issue in C# as well).

Display an Adorner over a WebBrowser control

I'm using the System.Windows.Controls.WebBrowser for various things in my app and I've noticed that adorners are cut off when they are supposed to appear over a WebBrowser. I realize that the WebBrowser control is really a wrapper around a COM component and probably renders differently, but I wondered if anyone figured out how to solve this.
This is the problem I'm seeing. Here I have just a sample adorner that is supposed to draw a big red circle in the top corner of something (as a sample).
When I adorn the WebBrowser with this, I get this result:
I expect to see the full circle.
Here's the code for this worthless adorner, in case that is helpful:
public class SillyAdorner : Adorner
{
public SillyAdorner(UIElement element) : base(element)
{
}
protected override void OnRender(DrawingContext drawingContext)
{
drawingContext.DrawEllipse(new SolidColorBrush(Colors.Red), new Pen(), new Point(7, 7), 30, 30);
base.OnRender(drawingContext);
}
}
And here is how I apply it to the browser in the OnRender method of the host control:
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
var layer = AdornerLayer.GetAdornerLayer(browser);
layer.Add(new SillyAdorner(browser));
}
Anyone have any hacks or workarounds for this?
Edit: I'm using .NET 4.0, if that makes a difference.
Edit #2: WebBrowser appears to inherit from HwndHost, which I've seen another question or two regarding adorners and hwndsources, but I'm not seeing anything that looks like I could implement it for the WebControl, but hopefully this is useful information for someone.
I don't think that will work with an Adroner, but you can float content over a WebBroswer control using a transparent Popup control. More details and a code sample can be found here.
Here's my blog post introducing a library I wrote for layering a WPF adorner over any hwnd. A simple web browser demo looks like this:
This is caused by airspace issues. Since a WebBrowser is a native, non-WPF control, there is no way to directly render adorners (or other WPF content) on top of it.
In order to do this, you need to use a separate window of some sort, and put the content into that separate window. This typically means using a transparent WPF window layered over the top of your main window. Unfortunately, this will not be as integrated of a solution as a true native WPF control would provide.
Try use another transparent TOP LEVEL overlay window. Only supported on Windows 2000 or higher of course, Win9x does not have layered windows.

performance in C# Application

i use some pictures in my 'MainForm' And My Windows Application was writing by c sharp.
i use this form to start other forms in my project.
And I use some label and panel with Transparent Color.
but when the program started i see many blink in transparent label and panel.
And it is very bad.
How I Can Fix this problem?
Enabling DoubleBuffered as stax suggested above is helpful but it may not be sufficient.
In your form, add the following method override:
protected override void OnPaintBackground(PaintEventArgs e) {}
And, in the OnPaint method, paint the background yourself instead. If you don't do this, drawing the background and painting are separate events, and background painting has higher priority, meaning that it will happen earlier.
Furthermore, if you add child controls (like labels), they receive their own paint background/paint events. You may be able to disable the Label's background. If I do stuff like this, I tend to not use controls but paint the text and the images in one OnPaint.
did you test it on multiple machines.
did you use an updated machine with all the .net service packs needed.
etc

What causes a window to not appear in the taskbar until it's Alt-Tabbed to in Vista?

When our app is started programatically (either through custom action in MSI installer or when starting a new instance) in Windows Vista (also happens in Windows 7 Beta) it won't appear in the taskbar and isn't focused. Alt-tabbing to it will make it appear in the taskbar properly and stay there.
What causes this? I've seen this in some other apps before as well, but not sure why. Out app is .NET WinForms app. Never see this happen in XP, only Vista and 7
Edit: Well, it seems like the only time this happens reproducibly is when it's run by the installer, I believe there's other times it occurs, but I might just be crazy. The launching code is a bit complex to post because we handle various command line launch parameters and it launches a signin form before actually launching the main app etc.
Has anyone had to deal with this scenario before and worked it out?
Try checking your main application form "Form Border" property.
If it's ToolWindow (Fixed or Sizable), try changing it to FixedDialog for example.
This solved the problem in my case.
The usual reason for this is that your main application window doesn't have the window styles that let Windows know it's a main application window (rather than a tool window or a dialog box). So Windows is having to guess based on how the app was started, etc.
Use Spy++ to complare the window styles (especially extended styles) if your window to that of some other window that doesn't have this problem. Are you missing the WS_EX_APPWINDOW style? Are any other styles/extended styles different from other top level windows?
G.So's answer made me find the solution for my problem, wich was caused by the fact that i had my form sizable from launch, but set to borderless in the load void.
If anyone is interested in how i managed to keep the switch to borderless and have it pop up as it should in the taskbar without any dirty hacks.. here it is..
Make a new event from the form on the form's "Shown" event, and put your line of code for switching to borderless in here. Problem solved :)
private void Form1_Shown(object sender, EventArgs e)
{
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
}
and for the lazy ones ;) >>>>
this.Shown += new EventHandler(Form1_Shown);
Thanks again G.So for clearing up what could cause this in the first place.
I stuggled with this issue as well, and found like a previous commenter said, you cannot have anything in the form's Load() event that changes that FormBorderStyle property. Move anything that changes it to the Shown() event.
Well, one solution is to use a hack like this. That's really not what it's for.
Usually the decision of whether a window will be in the taskbar or not is based on the border styles it uses. The article I linked to provides a bit more detail. The article's comment about the window having an owner or not is quite possible highly relevant to your issue, since the window might somehow be getting a different owner when launched by the installer.
That article is in VB but it's all based around API calls so the info it provides is pretty language independent.
Never see this happen in XP, only Vista and 7
Maybe it's a bug in Vista...?
What happens if you call SetForegroundWindow() (or equivalent in .Net)?
Edit
I did of course mean "BringWindowToTop()".
Or do both.
We had this same problem and fixed it by setting the form property showintaskbar property to true.
Weird that all windows os's dont run apps in the same way!
In our situation, this was tracked down to the form's text property being changed within the Load event.
After putting this inside a BeginInvoke, this odd behaviour no longer happened.
Hope this helps anyone else.
Example
private void Form_Load(object sender, EventArgs e)
{
...
...
...
// this needs to be inside a BeginInvoke otherwise it messes with the taskbar visibility
this.BeginInvoke(new Action(() =>
{
this.Text = "Something new";
}));
...
...
...
}
We encountered the same issue, also in Windows 8. Sometimes the form was receiving correctly the focus, but say just ~30% of the time.
We tried different solutions, but actually the one that worked was the following:
private void OnFormShown(object sender, EventArgs e)
{
// Tell Windows that the Form is a main application window
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
// Even if true, enforce the fact that we will the application on the taskbar
this.ShowInTaskbar = true;
// Put the window to the front and than back
this.BringToFront();
this.TopMost = true;
this.TopMost = false;
// 'Steal' the focus.
this.Activate();
}
Moreover, we ensure also not to set the title of the form during the Load event.

How do I hide the input caret in a System.Windows.Forms.TextBox?

I need to display a variable-length message and allow the text to be selectable. I have made the TextBox ReadOnly which does not allow the text to be edited, but the input caret is still shown.
The blinking input caret is confusing. How do I hide it?
You can do through a win32 call
[DllImport("user32.dll")]
static extern bool HideCaret(IntPtr hWnd);
public void HideCaret()
{
HideCaret(someTextBox.Handle);
}
When using the win32 call don't forget to hide the cursor in the textbox's GotFocus event.
Just for completeness, I needed such a functionality for using with a DevExpress WinForms TextEdit control.
They already do provide a ShowCaret and a HideCaret method, unfortunately they are protected. Therefore I created a derived class that provides the functionality. Here is the full code:
public class MyTextEdit : TextEdit
{
private bool _wantHideCaret;
public void DoHideCaret()
{
HideCaret();
_wantHideCaret = true;
}
public void DoShowCaret()
{
ShowCaret();
_wantHideCaret = false;
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
if (_wantHideCaret)
{
HideCaret();
}
}
}
To use the code, simply use the derived class instead of the original TextEdit class in your code and call DoHideCaret() anywhere, e.g. in the constructor of your form that contains the text edit control.
Maybe this is helpful to someone in the future.
If you disable the text box (set Enable=false), the text in it is still scrollable and selectable. If you don't like the visual presentation of a disabled text box (gray background usually) you can manually override the colors.
Be warned, manually overriding colors is going to make your form/control look weird on systems that do not use the default color/theme settings. Don't assume that because your control is white that everyone's control is going to be white. That's why you should always use the system colors whenever possible (defined in the System.Drawing.SystemColors enumeration) such as SystemColors.ControlLight.
I know this is an old thread but it is a useful reference.
I solved the problem with a much easier but very kludgie solution, which may depend on how much control you have over the user's access to the form. I added a textbox (any focus-able control) which I gave prime tabIndex value and then positioned it off-form so that it was not visible. This works fine on a dialog because the user can't resize. If the form is resizeable, this may not work.
As I said, a kludge - but a lot easier to set up. (BTW I found the HideCaret approach didn't work - but I didn't pursue it hard.)
AFAIK, this cannot be done. The TextBox control is a funny control because it actually has a lot of behaviour that can't be modified due to the way it taps into the operating system. This is why many of the cool custom TextBoxes are written from scratch.
I am afraid you may not be able to do what you wish to do :(

Resources