How to Delete selected control in Winforms C#? [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
i need that when you click a garbage button, the "Selection mode" turn on (A bool variable became true) and when you click that control (let's say a button) the application "selects it" and with another button, (Ok button) the application should knew Wich controls you clicked, and then, delete them, the problem i Have is in the recognize witch controls you selected
update
For "selection" I mean that the app knows which control you clicked

You can implement the required functionality as follows. The idea is simple, to keep track of our last selection we have a "previousSelection" variable of type "Control" in our class. We can even use a list of type "Control" to keep track of multiple selections.
There's a toggle button to enable / disable "Garbage Mode" which maps to "IsGarbageModeEnabled" field of type "bool". Then we have an "InitControlsRecursiveMethod(ControlCollection collection)" which takes in a collection of controls, to which we would attach an event handler, which is "GenericClickHandler(Control c)" in our case. This handler simply updates the "previousSelection" on each button click.
And lastly we have our button "ConfirmDeletionBtn", upon clicking which, we would check whether "GarbageMode" is enabled or not, if it is, we would have some basic validation to check whether the control being deleted isn't our "Delete" or "GarbageModeToggle" button itself (this could cause trouble if user double clicks the 'Delete' button). Afterwards, it would remove / dispose the control that is to be deleted.
public partial class FormName : Form
{
//To keep track of the previously selected control (i.e. to be deleted)
private Control previousSelection { get; set; }
//To keep track of whether "Garbage Mode" is enabled or disabled
private bool IsGarbageModeEnabled { get; set; }
//Constructor
public FormName()
{
InitializeComponent();
IsGarbageModeEnabled = false;
previousSelection = new Control();
//Attach a generic click handling event to each control to
//update "previousSelection" with each click.
//Similar logic can be used for other events as well
//(e.g. GotFocus, which might even accomodate control selection via keyboard).
InitControlsRecursive(this.Controls);
}
//This attaches the GenericClickHandler(Control c) to each control on the form.
private void InitControlsRecursive(Control.ControlCollection collection)
{
foreach (Control c in collection)
{
c.MouseClick += (sender, e) => { GenericClickHandler(c); };
InitControlsRecursive(c.Controls);
}
}
//The generic click handling event we're using to update "previousSelection".
private void GenericClickHandler(Control c)
{
previousSelection = c;
}
//By clicking the confirm deletion / OK button, we would delete the last selected control.
private void ConfirmDeletionBtn_Click(object sender, EventArgs e)
{
if(IsGarbageModeEnabled == true)
{
if(previousSelection != ConfirmDeletionBtn || previousSelection != ToggleGarbageModeBtn)
{
this.Controls.Remove(previousSelection);
previousSelection.Dispose();
}
}
}
//This is used to enable/disable Garbage Mode. Controls can be deleted only once it is enabled.
private void ToggleGarbageModeBtn_Click(object sender, EventArgs e)
{
IsGarbageModeEnabled = !IsGarbageModeEnabled;
}
}
Further Reading:
Handling a click for all controls on a form
Removing a control from a form

Firstly you need somewhere to keep track of the controls that were "selected" (clicked). So add this to the form's codebehind:
List<Control> _itemsToDelete = new List<Control>();
And you need a flag to indicate whether the user has activated garbage mode:
bool _garbageMode = false;
To activate garbage mode:
async void GarbageMode_Click(object sender, EventArgs e)
{
_garbageMode = true;
}
Now when they "select" a control you add it to the list:
async void Control_Click(object sender, EventArgs e)
{
if (_garbageMode)
{
_itemsToDelete.Add((Control)sender);
}
}
Then to delete
foreach (var control in _itemsToDelete)
{
this.Controls.Remove(control);
control.Dispose();
}
_itemsToDelete.Clear();

Related

All buttons state change in C# [duplicate]

This question already has answers here:
How to get ALL child controls of a Windows Forms form of a specific type (Button/Textbox)?
(28 answers)
Closed 2 years ago.
What I am trying to do is to change background color of the button once it's active. So far I achieved it by this way:
private void button3_Click(object sender, EventArgs e) // METEO BUTTON
{
DefaultButtons();
button3.BackColor = Color.LimeGreen;
// REST OF THE CODE HOES HERE
}
While DefaultButtons function is like this:
public void DefaultButtons()
{
List<Button> buttonsToDefualt = new List<Button>()
{
// MAIN MENU
button1,
button2,
[...]
buttonX
};
foreach (var item in buttonsToDefualt)
{
item.BackColor = Color.Green;
}
}
Now swapping buttons works like this: Change entire list to default color, then activated button change color to LimeGreen. It would be fine but:
1) I have to launch DefaultButtons(); for EACH button Click
2) I have to manually add all buttons to list, and now I have more than 120 buttons (Yeah, building custom interface...), and keep adding that by hand is tiring.
I tried this:
void DefaultButtonsNew()
{
foreach (Button b in this.Controls)
{
if (b != null)
{
b.BackColor = Color.Green;
}
}
}
But I've got an Exception: System.InvalidCastException: 'Can't throw object 'System.Windows.Forms.SplitContainer' on type 'System.Windows.Forms.Button'.'
If you're looking for a way to reset all buttons on the form, and some buttons are inside other containers, then we need to recursively loop through each control's Controls collection to find all the buttons.
One easy way to do that is to write a method that takes in a container (like the form), iterates through its Controls collection, changes the BackColor of any Button controls, and calls itself for the other control types:
private void ResetButtons(Control container)
{
// Loop through each control in this container
foreach (Control control in container.Controls)
{
var button = control as Button;
// If the control is a button, change it's backcolor
if (button != null) button.BackColor = Color.Green;
// Otherwise check it's controls collection (recursive call)
else ResetButtons(control);
}
}
Next, it sounds like you're looking for a way to avoid writing out a call to this method, and to change the BackColor of the current button, in every button click event.
One easy way around this is to simply add this method, and the BackColor change, to every button click in code. We can write a method to do this using a similar pattern - loop through every control in every container, and if it's a button, add a method to it's click event:
private void HookupButtonClickEvent(Control container)
{
// Loop through each control in this container
foreach (Control control in container.Controls)
{
var button = control as Button;
// If the control is a button, add a method to it's click event
if (button != null)
{
button.Click += (s, e) =>
{
ResetButtons(container);
button.BackColor = Color.LimeGreen; // Change this button's color
};
}
// Otherwise check it's controls collection (recursive call)
else HookupButtonClickEvent(control);
}
}
Now, all we have to do is call the ResetButtons and HookupButtonClickEvent in our form's constructor, and every button will start with the same backcolor and will have our reset method call in it's click event:
public Form1()
{
InitializeComponent();
HookupButtonClickEvent(this);
ResetButtons(this);
}
Note that this does not prevent you from adding additional click events to the buttons. It merely provides a way to hook up the common functionality to all buttons without writing a bunch of duplicated code.
You can still double-click the controls on your form to add other Click event handlers:
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Button one clicked - doing something unique here");
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("Button two clicked - doing something else here");
}
The iterator on Controls collection returns all the controls and trying to cast it to Button should an do fail.
Change your method like this:
void DefaultButtonsNew()
{
foreach (Control b in this.Controls)
{
if (b is Button)
{
b.BackColor = Color.Green;
}
}
}

Click event not firing for custom UserControl on a form

I have created a UserControl called Toggle, this is my code for it
[DefaultEvent("Click")]
public partial class Toggle : UserControl {
public bool ToggleStatus { get { return toggleStatus; } }
private bool toggleStatus { get; set; }
public Toggle() {
InitializeComponent();
toggleStatus = true;
}
private void toggleClick(object sender, EventArgs e) {
if (toggleStatus) { // currently set as "true" or "on"
this.lblSwitch.Dock = DockStyle.Right;
this.pnlBackground.BackColor = System.Drawing.Color.Red;
toggleStatus = false;
} else { // currently set as "false" or "off"
this.lblSwitch.Dock = DockStyle.Left;
this.pnlBackground.BackColor = System.Drawing.Color.Green;
toggleStatus = true;
}
}
}
The toggleClick method is tied to the click event of controls within the UserControl; this fires off just fine.
However, when I put my Toggle control on a form and attempt to tie an event to the click of it, it won't fire off.
private void toggleSoundClick(object sender, EventArgs e) {
soundToggle = !soundToggle;
}
I've made sure that the proper method is tied to the click event in my Designer.cs file of both my UserControl and my form
UserControl:
this.lblSwitch.Click += new System.EventHandler(this.toggleClick);
this.pnlBackground.Click += new System.EventHandler(this.toggleClick);
(I have it tied to two controls on my Toggle since I want it to fire no matter where you click on the control)
Form:
this.tglSound.Click += new System.EventHandler(this.toggleSoundClick);
The expected behavior for the UserControl is to fire off toggleClick (which it does) then the form should fire off toggleSoundClick (which it doesn't). I have seen this behavior work fine for other UserControls I have designed and used in this same project.
To clarify:
I have a UserControl called ServerDisplay. I have a method tied to the click event of the background panel of ServerDisplay (in the code for ServerDisplay) that shows a random MessageBox:
private void ServerDisplay_Click(object sender, EventArgs e) {
MessageBox.Show("test");
}
Then, I have a ServerDisplay control contained within my form. I have a method tied to the click event of it as well (in the code for my form)
private void serverDisplayClick(object sender, EventArgs e) {
if (loaded) {
ServerDisplay display = (ServerDisplay)sender;
this.lblLastServer.Text = "Last server joined was " + display.Server.Name + " at " + DateTime.Now.ToString("h:mm tt");
centerControl(this.lblLastServer);
}
}
When I click on the ServerDisplay control in my form, it shows the MessageBox (code from within ServerDisplay), then updates the label I specified in the code (code from form). This is the intended behavior, but it is not working for my other UserControl.
I finally figured it out! The way I had the control set up, I had the control itself, a panel filling up the entire background (I used this for the color), and then another panel inside the first panel to act as the "switch".
When I got rid of the first panel and just used the background of the control for the color and a small panel for the switch, it works when I click the background, but not when I click the "switch" panel. I guess this opens up more questions that I'll have to ask separately from this one, but at least I got my answer.

Hiding datagridviews bug

I have a windows form with a panel on the left, which consists purely of radiobuttons, and a tabcontrol in the middle, with multiple tab pages within it. Each of these individual tabpages have a series of datagridviews within it, which are shown and hidden depending on which radio button you check.
I accomplish this effect by having each of the radiobuttons on the left assigned a CheckChanged event, which loops through all of the controls within the tabpagecontrol.SelectedTab, and calls .Show() on the corresponding datagridview and calls .Hide() on the rest so that only one datagridview is visible at one time.
My problem occurs when i try to programmatically check one of these RadioButtons. Lets say in Method X, I write RadioButtonA.checked = true. This triggers the usual CheckedChange event handling, which loops through all the datagridviews on the currently selected tabpage and calls .Hide() on everything except the one datagridview form that the radiobutton is supposed to bring up and calls .Show() instead. However, on one of these .Hide() calls on the datagridview, it ends up triggering the RadioButtonA.CheckedChange event AGAIN for a second time. When i look at the sender argument passed to the function, it shows that the sender is the RadioButton i just programmatically clicked on.
I am adding these datagridviews programmatically and can confirm that there are no eventhandlers assigned whatsoever to them. Can anyone help me determine what is causing this additional event to get triggered? Thanks.
For obnoxious change events that trickle through and upset other event handlers on my forms, I've found the only solution is to add a small boolean value:
bool radioIng;
void MyMethod() {
radioIng = true;
try {
radioButton1.Checked = true;
// etc.
} finally {
radioIng = false;
}
}
void radioButton_EventHandler(object sender, EventArgs e) {
if (radioIng) return;
// rest of code here
}
EDIT:
Alternately, you could just remove all of your event handlers and reconnect them later:
void MyMethod() {
try {
radioButton1.CheckChanged -= radioButton_EventHandler;
radioButton2.CheckChanged -= radioButton_EventHandler;
radioButton3.CheckChanged -= radioButton_EventHandler;
// execute your code
radioButton1.Checked = true;
} finally {
radioButton1.CheckedChanged += new EventHandler(radioButton_EventHandler);
radioButton2.CheckedChanged += new EventHandler(radioButton_EventHandler);
radioButton3.CheckedChanged += new EventHandler(radioButton_EventHandler);
}
}
void radioButton_EventHandler(object sender, EventArgs e) {
if (sender == radioButton1) {
// code here to handle
} else if (sender == radioButton2) {
// code here to handle
} else if (sender == radioButton3) {
// code here to handle
}
}

How do I detect a change of tab page in TabControl prior to SelectedIndexChanged event?

I currently determine what page of a tabcontrol was clicked on via the SelectedIndexChanged event.
I would like to detect before the selected index actually changes, for validation purposes. For example, a user clicks a tab page other than the one they are viewing. A dialog is presented if form data is unsaved and asks if it's ok to proceed. If the user clicks no, the user should remain on the current tab.
Currently I have to remember the previous tab page and switch back to it after an answer of 'no.'
I considered MouseDown (and the assorted calculation logic), but I doubt that's the best way.
Add such an event to the tabControl when form_load:
tabControl1.Selecting += new TabControlCancelEventHandler(tabControl1_Selecting);
void tabControl1_Selecting(object sender, TabControlCancelEventArgs e)
{
TabPage current = (sender as TabControl).SelectedTab;
// Validate the current page. To cancel the select, use:
e.Cancel = true;
}
I've actually tried all of the events including the suggestions here and none of the mentioned events occur at the right time to actually trap moving from the tab.
Even the tab page validation event fires when entering the tab rather than leaving it - either that or there's something peculiar going on with my machine or .NET 4. On the other hand, in .NET 4 there is the Deselecting event which fires at the right time for my purposes.
private void tab_Deselecting(object sender, TabControlCancelEventArgs e)
{
}
The TabControl has a collection of TabPages, each of which you can enforce validation on, e.g.:
public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
foreach (var page in _tabControl.TabPages.Cast<TabPage>())
{
page.CausesValidation = true;
page.Validating += new CancelEventHandler(OnTabPageValidating);
}
}
void OnTabPageValidating(object sender, CancelEventArgs e)
{
TabPage page = sender as TabPage;
if (page == null)
return;
if (/* some validation fails */)
e.Cancel = true;
}
}

Disabling buttons problem on C#

Ok so I'm trying to move items from one listbox to another by using multiple buttons i.e
I have 2 buttons cmdRight and cmdRight2 which are both disabled on form load
If the user selects a single item on the first listbox a cmdRIght button enables but cmdRight2 is still disabled , if the user selects multiple items on the first listbox a cmdRight2 button enables but cmdRight is disabled.
I've got the move buttons to work but the problem I'm having is after moving multiple items with the cmdRight2 button the cmdRight button enables (which it shouldn't it should only enable after selecting a single item in the listbox). I've tried numerous if statements etc. and yet it still happens.
I'm new to C# so any help would be appreciated.
Thank You
private void lbList1_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.lbList1.SelectedItems != null)
{
cmdRight.Enabled = true; //enable cmdRight
cmdClear.Enabled = true; //enable cmdClear
if (this.lbList1.SelectedItems.Count > 1)//if multiple items selected
{
cmdRight.Enabled = false;
cmdRight2.Enabled = true; //enable cmdRight2
}
}
}
private void cmdRight2_Click(object sender, EventArgs e)
{
foreach (int i in lbList1.SelectedIndices)
{
lbList2.Items.Add(lbList1.Items[i].ToString());
}
while (lbList1.SelectedItems.Count > 0)
{
lbList1.Items.Remove(lbList1.SelectedItems[0]);
}
cmdRight2.Enabled = false;
}
private void cmdRight_Click(object sender, EventArgs e)
{
lbList2.Items.Add(lbList1.SelectedItem); //Add selected item from list1 to list2
lbList1.Items.Remove(lbList1.SelectedItem);//remove the selected item in list1
cmdRight.Enabled = false; //disable cmdRight
}
How about creating one method EnableButtons that enables/disables to buttons according to given criteria like "enable cmdRight2 only if.... is true".
Then, call the method whenever some of the criteria might change. The advantage of this over the way you're doing it now is that the criteria within the method are "absolute" (in that the buttons are either enabled or disabled in one go) instead of "relative" (enable the button when the user does this or that).
You could also call this method from the Application.Idle event instead of calling it in response to some user action.
EDIT
Declare the following method:
private void EnableButtons()
{
controlX.Enabled = (<condition...>);
controlY.Enabled = (<condition...>);
}
You can either invoke that method from the positions in code where something should change in the buttons' enabled states, or you can do the following in the constructor of the form:
public Form1()
{
// Other code...
Application.Idle += new <The respective event handler>;
}
Then, declare a method with the respective signature for the event and call EnableButtons there. This method would be called in situations where your application is "idle" (waiting for user actions).
I think you want
if (this.lbList1.SelectedItems.Count == 1)
{
}
else if(this.lbList1.SelectedItems.Count > 1)
{
}
else
{
}
instead of
if (this.lbList1.SelectedItems != null)
Then you could place all of this in a method called "EnableButtons" as mentioned elsewhere
The problem is that you are removing the items one by one, so when only one item is left, you essentially have one item selected so your program enables the cmdRight. The easiest way around this is to have
cmdRight2.Enabled = false;
cmdRight.Enabled = false;
at the end of the cmdRight2_Click method.

Categories

Resources