TabControl Cancel change of tabs - c#

I am using TabControl_SelectedIndexChanged event when the user change tabs. The TabControl.SelectedIndex / TabControl.SelectedTab return only the new tab. Is there any way I can get the previous tab? Or must I stick with the obvious store the current tab every time I change tabs?
I want to use this to cancel a change of tabs under certain conditions, like there is unsaved changes.

If you want to cancel the change of a tab, you can use the Deselecting event. There you can cancel the change by setting property Cancel of the provided TabControlCancelEventArgs to true.

Check out http://msdn.microsoft.com/en-us/library/system.windows.forms.tabcontrol.selected%28v=vs.80%29.aspx
There are events better suited for what you want to do.

I used tabControl Selected method to prevent users selecting a certain tab, in other word, to disable a tab page.
TabPage currentPage;
private void tabControl1_Selected(object sender, TabControlEventArgs e)
{
if (e.TabPage == tabNotAllowed)
{
tabControl1.SelectedTab = currentPage;
MessageBox.Show("You cannot use the tab you selected.");
}
else
{
currentPage = e.TabPage;
}
}

Related

Hiding TabPage from TabControl in Winform application

I have a TabControl in Winform s application,
I have to disable the second tab, clicking it would be enabled only after some action on my first page.
I have achieved this by disabling tab by code
tabControl1.TabPages[1].Enabled = false;
But I want that tab to be hidden or clicking the tab itself should be disabled.
Try This. It will hide and show the TabPages without a Control lost.
Hide TabPage and Remove the Header:
this.tabPage1.Hide();
this.tabPage3.Hide();
this.tabPage5.Hide();
tabControl1.TabPages.Remove(tabPage1);
tabControl1.TabPages.Remove(tabPage3);
tabControl1.TabPages.Remove(tabPage5);
Show TabPage and Visible the Header:
tabControl1.TabPages.Insert(0,tabPage1);
tabControl1.TabPages.Insert(2, tabPage3);
tabControl1.TabPages.Insert(4, tabPage5);
this.tabPage1.Show();
this.tabPage3.Show();
this.tabPage5.Show();
tabControl1.SelectedTab = tabPage1;
You have asked two questions:
How to hide a TabPage
How to make it non-selectable
You can't really hide a TabPage; the closest and simplest solution is to remove it from the orginal Tab control and add it to a hidden helper Tab control:
tabPage3.Parent = helperTab;
To make it non-selectable, you code the Selecting event of the Tab control. You need to set a flag, maybe in the Tag of the page, and then you can prevent a page where the flag is set from being selected:
private void tabControl1_Selecting(object sender, TabControlCancelEventArgs e)
{
if (e.TabPage.Tag == "X") e.Cancel = true;
}

How to trigger event when clicking on a selected tab page header of a tab control

I am doing a Winform application in C# and I have some tab pages, say tabPage1, tabPage2 and tabPage3, in a tab control, and tabPage1 is selected.
I want to trigger event when any tab page header is clicked, but I could do it only for page change (by using SelectedIndexChanged) but not click on a selected tab page header.
I tried with Selecting and Selected events but both of them didn't not work. I searched on MSDN but didn't find any Click event defined on a page header. So how should I achieve this?
One further question, is it possible, and how, to detect DoubleClick on a selected tab page?
Just use the tabcontrol's MouseDoubleClick event. You'll have to iterate the tabs to find out what specific tab was clicked:
private void tabControl1_MouseDoubleClick(object sender, MouseEventArgs e) {
for (int ix = 0; ix < tabControl1.TabCount; ++ix) {
if (tabControl1.GetTabRect(ix).Contains(e.Location)) {
// Found it, do something
//...
break;
}
}
}
Do keep in mind that this is completely undiscoverable to the user, he'll never think to double-click the tab. You'll have to write a manual.
You should be doing your stuff on
TabIndexChanged
If you want to load the contents on your 3rd tab, for example, handle the TabIndexChanged on your tab control, do a switch for each tabPage.Index and then do whatever is needed when user clicks on that tab.
private void tabPage1_Layout(object sender, LayoutEventArgs e)
{
//do something
}

Tab index is not working on radio buttons

This is the part of my form that I am asking about
This is the tab index:
The problem that the tab goes from Farmer Audi Status to Yes, then to Ownder Bank Name instead of going to No
please notice that the yes and no already have 0.1.6.0 and 0.1.6.1 respectively.
could you help me please?
Notice
both radio buttons has TabStop property to True
From How to: Set the Tab Order on Windows Forms (MSDN):
A radio button group has a single tab stop at run time. The selected button (that is, the button with its Checked property set to true) has its TabStop property automatically set to true, while the other buttons have their TabStop property set to false.
In other words, what you're seeing is normal. Those "Yes/No" radio buttons are in the same group, and you can't tab between radio buttons in the same group. As you tab, you'll only focus on the currently selected one, then move to the next control on the form (in your case, a TextBox).
To work around this, you could place each radio button in its own container (such as a Panel), which means you'd have two "groups" each with one radio button. But then you lose the built-in functionality that automatically deselects one radio button when you select the other. Your user will be able to select both radio buttons, so you'd need to add some logic that disables the other. If you decide to try that, experiment with the radio buttons' CheckedChanged or Click / MouseClick events.
As Steve said, and as stated in the answer he linked to, the way it works out-of-the-box is expected behavior for Windows, so think twice before overriding it unless you have a good reason for doing so.
It worked for me!
first you have to create a method like this:
private void TabStopChanged(object sender, EventArgs e)
{
((RadioButton)sender).TabStop = true;
}
and then, put this in your Form_Load event:
private void Form_Load(object sender, EventArgs e)
{
foreach (var item in this.Controls)
{
if (item.GetType() == typeof(RadioButton))
((RadioButton)item).TabStopChanged += new System.EventHandler(TabStopChanged);
}
}
For radio buttons, you don't have to use Tab to navigate. Just use right and left keys to traverse radio buttons.
Check out this link to read more - https://www.csun.edu/universal-design-center/web-accessibility-criteria-tab-order

Detect if mouse click hits a item not in listbox [C#]

If the user click on a item in the listbox, the listboxItems_SelectedIndexChanged is called. But, even if the user miss an item and randomly clicks inside the listbox (not on items) the listboxItems_SelectedIndexChanged is still called.
How can I change this? I only want action on item click.
Note: removing the ability to navigate the application with keyboard is not a option.
I guess that in some cases you don't have enough list items in your control, therefore you have some space that you can click on and then SelectedIndexChanged is fired.
I guess you cannot dynamically resize the control to always fit the number of list items or else you wouldn't be asking this question.
Now, what should happen when the user click (selects) the same list item? Should some logic happen even though the selected index is the same (so when it was clicked the first time the same logic happend)?
If you require that selecting the same index more than once should be ignored then you could use the following hack:
Keep a variable at the form scope (the form containing the listbox control) and each time the selection index changes set that variable. Then use it later to check if the same selection has been made to ignore handling the event. Here is an example:
private int _currSelIdx = -1; // Default value for the selected index when no selection
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBox1.SelectedIndex == _currSelIdx)
return;
Console.WriteLine(listBox1.SelectedIndex);
_currSelIdx = listBox1.SelectedIndex;
}
It ain't pretty, but hey...whatever works!
Maybe SelectedIndexChanged is not the right place to put your logic, since it is triggered even when you change the selection with the keyboard.
I would use MouseClick instead, checking if the click occurred over the selected item, i.e. something like this:
private void listBox1_MouseClick(object sender, MouseEventArgs e)
{
if (listBox1.SelectedIndex < 0 || !listBox1.GetItemRectangle(listBox1.SelectedIndex).Contains(e.Location))
MessageBox.Show("no click");
else
MessageBox.Show("click on item " + listBox1.SelectedIndex.ToString());
}
This link may help, instead of double click, implement the same for single click
i want to detect an item double click in a winforms listbox control. [how to handle click on blank area?]

.NET UserControl accept button best practice?

I have a windows forms app where I have split different functionality into several user controls. I want each of these user controls to have an accept button.
Any best practices here?
My idèa is to detect which user control that has focus, and than set it in the parent Form.
Any other idèas?
The best practice is usually to only have one accept button for your form so that its behavior is consistent. It generally would be confusing for users if hitting return caused different actions depending on which section of the form had focus. However, if you have a specialized application or users have requested this feature then I think the solution you propose would work.
Jan Miksovsky has an excellent blog on UI design, and wrote an article about this very thing.
Most UI platforms allow a designer to
indicate which button in a dialog
should be the default button: the
button that will be pressed if the
user types the Enter key. The default
button is generally the button the
user is most likely to press next,
often a button like OK that closes the
dialog. In very high-traffic dialogs,
you may want to consider dynamically
changing the default button to save
keystrokes and help speed the user's
task.
The example he uses is the "Select Names" dialog in Microsoft Outlook, which changes the default button depending on what you are doing.
I assume each user button is its own instance on the individual user controls?
If so then you can trap the button events on the Parent form. If you expose the individual buttons through a property you can tie into their Click events. Like all controls they have a name property so you can have one method that is called on all button click events.
Below I have a partial sample code. I have two user controls that have one button each. The button on UC1 is named "btn1" and "btn2" for UC2. I call the exposed property "ButtonOK"
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public Button ButtonOK
{
get { return btn1; }
}
}
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
}
public Button ButtonOK
{
get { return btn2; }
}
}
Now on the parent ("Form1") when it loads have a mthod that ties into the Click events of each button but it calls the same method. Inside the method I test for the "Name" property.
public Form1()
{
InitializeComponent();
}
void Form1_Load(object sender, EventArgs e)
{
RegisterButtonEvents();
}
void RegisterButtonEvents()
{
userControl11.ButtonOK.Click += new EventHandler(ButtonOK_Click);
userControl21.ButtonOK.Click += new EventHandler(ButtonOK_Click);
}
void ButtonOK_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
if (btn != null)
{
if (btn.Name == "btn1")
{
Console.WriteLine(" ButtonOK from UserControl1 was pushed. The tag is " + btn.Tag.ToString());
}
else if (btn.Name == "btn2")
{
Console.WriteLine(" ButtonOK from UserControl2 was pushed. The tag is " + btn.Tag.ToString());
}
}
}
You can also user the "Tag" property of a control. This property can be very useful as it can reference objects.
You don't need to do exactly as shown but you can use any "Parent" form to get a reference to the UserControls, have them expose their Buttons, then you can do anything you want with properties and events from those Buttons (or any control for that matter).
Keep in mind that if you are tying into the click event on the user control also (in addition to the parent form), you will have to be mindful of the order in which it will enumerate through it list of delegates and execute code after the event is intiated.
Hope that helps.
I know this is an old post, but I think I figured it out.
Use the "Enter" event on each user control from the main form, such that when the user "enters" (focuses on) the user control, this.AcceptButton = myUserControlButton. You can also use the "Leave" event on each user control to set the accept button back to the default, if you have one.
I'm not sure if I understood your question correctly.
If you want to assign one event to several buttons:
For this you could for instance:
- Get the button name on the Button_Click event.
- Enumerate between names
- Iterate over the controls.
Example bellow:
"How to get the button name from the Button_Click event".
// First; dont forget to assign the "Button_Click" event to your Button(s).
private void Button_Click(object sender, EventArgs e)
{
// The line bellow assigns to "btn" variable the currently clicked button.
Button btn = (Button)sender;
// Then using a switch block; you can compare the button name and
// perform the action desired for the clicked button.
switch(btn.Name)
{
case "buttonName1": /* Do Something Here */ break;
case "buttonName2": /* Do Something Here */ break;
// etc
}
}
Additionally; if you require; there's always the way to retrieve the Button outside the form class by exposing them.

Categories

Resources