I have a one question on my university's test about C#. Could label get a focus? As I can see on MSDN site, all Controls can get a focus, but some of them aren't selectable. So it's seems to me that the right answer is "Label could get a focus, but couldn't be selected". Also Label has a Focus() method. Please, help me understand. Thanx.
Yes there is a Focus() method on Label and yes it is absolutely right it works; but behave differently. let me try to explain
A Label can be associated with some one input control, for instance a label for a user name text field, so there is concept of Associated Control with the label. AssociatedControlID on msdn
So you can associate an input control with a label and whenever label is selected the control passed to the associated input control.
Example here click on Email or Password labels in login box and see what happened, similarly if you call focus method on the label the focus will passed to the associated control.
From the documentation:
A control can be selected and receive
input focus if all the following are
true: the Selectable value of
ControlStyles is set to true, it is
contained in another control, and all
its parent controls are both visible
and enabled.
Since a Label control is not selectable, it cannot receive input focus, even if it inherits a Focus() method from Control. Therefore, the answer is no.
It's easy to findo out if a control's ca get focus. Just read the
.CanFocus
property which is inherited from the Control class.
The Windows Forms controls in the following list are not selectable. Controls derived from these controls are also not selectable. (see MSDN documentation)
Panel
GroupBox
PictureBox
ProgressBar
Splitter
Label
LinkLabel (when there is no link present in the control)
Also:
The Focus method returns true if the
control successfully received input
focus. The control can have the input
focus while not displaying any visual
cues of having the focus. This
behavior is primarily observed by the
nonselectable controls listed below,
or any controls derived from them.
A control can be selected and receive
input focus if all the following are
true: the Selectable value of
ControlStyles is set to true, it is
contained in another control, and all
its parent controls are both visible
and enabled.
If you need a Label-like control that you can focus, just use a TextBox and make it readonly. Set a few other properties (styles, not selectable etc.) and you're done.
You will see that there is a read only property called CanFocus on a label, if you have a look at this property while debugging you will see it is false.
Every control that inherits from Control has the focus method, but that does not mean that it can be focused.
Label does gets the focus but it escalates it to the input field specified in its "for" attribute. Like:
<label for="firstname">First Name</label><input type="text" name="firstname" />
In this scenario if you click on the label it will throw the focus to the input field "firstname" associated with it.
This is a year old, however I had a similar issue as the Op. In my case it was a user control that had a single label (docked at fill) on it (it has other functions behind the scenes - it is a calendar control and pops up a date picker - not the standard one - in either a panel (popunder) or a form (popup)).
The issue there was that UserControls are really intended as containers and resist focus (pushing it off to child controls) - as the label is the only child control, it stops the UserControl getting focus. Using readonly TextBox is a poor substitute as it lacks vertical alignment and must be multiline to size the height.
The reason I add the following as an answer here is because it IS possible (sorry guys who said here it is not) and I found this post and many like it that were little help when I looked. Anyway, the way to do it is to override the Label and set the SetStyle - also the OnPaint to draw a focus rectangle (I manually drew mine as DrawFocusRectangle didn't seem to do anything) - so as below:
internal class SelectableLabel: Label
{
public SelectableLabel():base()
{
SetStyle(ControlStyles.Selectable, true);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
//ControlPaint.DrawFocusRectangle(e.Graphics, ClientRectangle);
if (!Focused) return;
if (BorderStyle == BorderStyle.Fixed3D)
{
e.Graphics.DrawLines(Pens.CadetBlue, new[] { new Point(1, Height - 1), new Point(1, 1), new Point(Width - 1, 1) });
e.Graphics.DrawLines(Pens.Aquamarine, new[] { new Point(2, Height - 1), new Point(Width - 1, Height - 1), new Point(Width - 1, 2) });
}
else
{
e.Graphics.DrawRectangle(Pens.Aquamarine, 0, 0, Width - 1 , Height - 1 );
}
}
}
I am not concerning myself on whether it is accademically (purist view) right to do so, but that there are valid reasosn to allow an output control (like label) to sometimes gain focus.
Related
I'm creating an application in Forms for very non tech-savvy users. In doing so, I'm attempting to keep some more complicated buttons and menus hidden in the main program unless an invisible checkbox is checked- which only the QA/Dev team would need to use for troubleshooting.
I've attempted to use checkBox1.Hide() followed by checkBox1.Show on click as well as on CheckedChanged, however when the checkbox is hidden or has visibile set to false, the checkbox is unable to be checked. I've also looked at the checkbox's properties window in the Form design, but setting the bordercolor to white or the bordersize to 0 under FlatAppareance had no effect.
Any suggestions? Thanks for the help.
I agree with the comments this is not a good practice when designing a user interface, but there is a way to make an invisible button in winforms.
in your constructor or in a method set the properties of the button like so
button1.FlatStyle = FlatStyle.Flat;
button1.FlatAppearance.BorderColor = BackColor;
button1.FlatAppearance.MouseOverBackColor = BackColor;
button1.FlatAppearance.MouseDownBackColor = BackColor;
this will render a invisible to the user button that can be clicked. that is if your click event is already set up.
i'm using telerik control.
So i want to ask,
In winforms application ,Is it possible to add more than one panel in same location and display one at a time just like show/hide property.
Make sure you have placed all panel control in same container or form. then you can use Visible property to show and hide panel. BringFront and SendToBack function will be used to bring panel on top or send it to back. If you have placed any panel in another panel then that will be disappeared when you Hide parent panel. So, Make sure all panels' parent control must be same. To determine the parent control simply select that panel and press escape key to select their parent.
private void LoadPanels()
{
panel1.Location = new Point(10,10);
panel2.Location = new Point(10,10);
panel3.Location = new Point(10,10);
panel4.Location = new Point(10,10);
panel5.Location = new Point(10,10);
VisiblePanel("panel1");
}
private void VisiblePanel(string panelName)
{
string[] panels = new string[]{"panel1","panel2","panel3","panel4","panel5"};
for (int i=0;i<panels.Length;i++)
this.Controls[panels[i]].Visible = (panels[i] == panelName);
this.Controls[panelName].BringToFront(); //Not required you can remove this line.
}
Here's a slightly different approach you might want to consider...
Are you wanting to be able to programmatically select the contents of a rectangular area at runtime, selecting among various controls to display? If so, you could use a custom TabControl which has its tabs (not the pages) hidden.
Then you can select which page is displayed by programmatically changing its SelectedIndex property at runtime.
Doing it like this means that your form editor will show a normal tab control, which allows you to much more easily add the content to each page - but at runtime the tabs will be hidden from the user; they will just see the contents of the currently selected page.
See Hans Passant's answer here for how to create such a custom tab control.
(However, you might also want to override the OnKeyDown for the custom tab control in order to ignore Ctrl-Tab.)
A form contains a DockPanel with an instance of DockContent which has DockState=DockState.DockBottomAutoHide and it acts as a logger view - like Visual Studio's Error list panel. So, when a logging event is added to log list, DockPanel - if is not visible - is shown in next way:
{
loggerList.AddLogEvent(event);
loggerContentPanel.Show();
};
but if loggerContentPanel is already visible for user, Show method make the panel to "blink".
Is any way to get the state of a DockContent with DockState = DockState.DockBottomAutoHide if is visible for user? IsHidden or Visible properties doesn't help too much.
EDIT: Alright... What I found is, when the panel is hidden, the property "IsActivated" is false, and is true when it's showing.
Are there any other methods of bringing a control to the front other than control.BringToFront()?
I have series of labels on a user control and when I try to bring one of them to front it is not working. I have even looped through all the controls and sent them all the back except for the one I am interested in and it doesn't change a thing.
Here is the method where a label is added to the user control
private void AddUserLabel()
{
var field = new UserLabel();
userContainer.Controls.Add(field);
SendLabelsToBack(); // Send All labels to back
userContainer.Controls[field.FieldName].BringToFront();
}
Here is the method that sends all of them to the back.
private void SendLabelsToBack()
{
foreach (var label in userContainer.Controls);
label.SendToBack();
}
Yeah, there's another way. The Controls.SetChildIndex() also changes Z-order. The one with index 0 is the one on top. Doesn't buy you anything though, BringToFront() uses this method.
Your SendLabelsToBack() method as given cannot work, it will also send the label to added to the back. But your next statement fixes that again.
Okay, that doesn't work, which means the BringToFront() method doesn't get executed. Look in the Output window for a "first chance exception" notification. As written, your SendLabelsToBack() will cause an exception if the user control contains any control other than a UserLabel. Also, set a breakpoint after the BringToFront() call and check the value of userContainer.Controls[0].Name when it breaks.
Controls' z-index is per-container.
If you call BringToFront on a control that is inside a container (such as a Panel), it will not bring the container to the front.
Therefore, the control will only go in front of other controls in that container.
To see what containers your controls are in, you can use the Document Outline pane in the View menu.
EDIT: Your userContainer control is probably behind a different control.
Have you tried Invalidate() after BringToFront()? BringToFront does not raise the Paint event
try this:
private void SendLabelsToBack()
{
foreach (var label in userContainer.Controls)
{
label.SendToBack();
label.Invalidate();
}
}
I think you just need to change your last line:
userContainer.Controls[field.FieldName].BringToFront();
to this:
userContainer.Controls[field.Name].BringToFront();
When you use a string as the indexer for the Controls collection, it goes by the Name property of the control (not the FieldName property).
Since you're just trying to bring the most recently-added control to the top, this would also work:
userContainer.Controls[userContainer.Controls.Count - 1].BringToFront();
From my experience looks like windows puts all controls belonging to one graphic container(pane, group box...etc) in a software collection. The collection is ordered by child index which is a property of every control in that container.
The trick is that children with the same index can and do exists. In this case windows will paint those children ordered relative to others but between them it will paint them in the reverse order they had been added to the container.
Long story short: for one container-you need to make sure controls have different indexes by changing ALL NOT just SOME of the indexes when you want to change the z-order. For example:
foreach (Control newControl in TopControl.Controls)
{
TopControl.Controls.SetChildIndex(newControl,indexlogic(newControl));
}
where indexLogic(newControl ) is your method of calculation of the index of particular control.
I have a control which contains a NumericUpDown. The updown is only shown when the container has focus, so the container has to be selectable (or else it could never receive focus). I want the control to behave as a single entity with regards to tab order; that is, when the user tabs to the control, it shows the updown and the updown is focused; when the user tabs away from the updown, it is as if they had tabbed away from the control.
It's easy enough to achieve the first part: in the container's OnEnter, I focus the updown. If the user tabs away without shift, it also works fine, since the next control in the tab order is the correct one. However, the previous control in the tab order to the updown is the container, since it had to be selectable; so when the user shift-tabs away from the updown, the container is selected, and therefore the updown gets selected again.
How do I select the previous control to the container control, when the user shift-tabs away from the updown?
UPDATE:
My problem isn't detecting when I need to do this - it's finding the control to send focus to.
UPDATE:
SelectNextControl only seems to work within the container's parent's controls; if the container is the only control on its parent, it doesn't change focus, even if there are other controls elsewhere in the hierarchy that ought to receive focus via tab.
if you know the direction of the tab you could use SendKeys.Send("+{TAB}"); and SendKeys.Send("{TAB}");
or you could use Control.SelectNextControl()
void UserControl1_Leave(object sender, EventArgs e)
{
this.numericUpDown1.Visible = false;
Control c = Parent.Controls[this.Name];
int i = Parent.Controls.IndexOf(c);
Parent.Controls[i - 1].Focus();
}
I've added this leave event to a custom control and its working for me. Basically when the user shift tabs away this event sets the focus to the previous control in the parent form's control collection. Don't know if its what your looking for exactly but hopefully it will send you in the right direction.
It's a hack, but you can use the OnEnter event coupled with a boolean variable. If the variable is set to true then you were already in your container and go to the previous control (which could be a property of your container control so you know where you are going).
If the variable is false, your just getting to your custom control and focus on the up/down.
On the exit of the container, set the variable back to false.
I'm sure there's something simpler out there, but offhand this is the quickest thing I can think of.
Actually this seems to be the default behavior for me?