C# - Trying to create a "selected" state for several buttons - c#

What I want to do is creating a menu with several buttons and when the user clicks on one of them, the selected button tag gets stored in a variable and the background color of that button gets highlighted. When the user clicks another button, the previous stored variable gets compared with the new variable and if it is different, it changes the background color of the earlier pressed button back to normal. This is what I have so far:
if (!isSelected)
{
b.BackColor = Color.FromArgb(28, 145, 162);
previousPress = (int)b.Tag;
isSelected = true;
if(previousPress != currentPress)
{
b(previousPress).BackColor = Color.FromArgb(12, 34, 567); // Obviously this wont work, but hopefully it clears up on what I want to reach.
isSelected = false;
currentPress = (int)b.Tag;
}
}
The .Tag idea of B is ranging from 1 till 7, as that is how many buttons are created in the constructor method.
That is what I tried to use, but someone suggested I shouldn't be using tags for this, as it should only cause bugs and errors. He suggested the following:
Button previousButton = b;
if (previousButton != currentButton)
...
I understand the logic behind this, but sadly before he went away before I could ask where and how the currentButton variable is declared/used. Could someone shine some light upon this? Thank you!

Assuming that all the buttons are assigned the same Click event, this code would do exactly what you want:
Color _activeColor = Color.Red;
private void buttons_Click(object sender, EventArgs e)
{
foreach (Button btn in this.Controls.OfType<Button>()
.Where(b => b.BackColor == _activeColor))
{
btn.BackColor = SystemColors.Control;
}
((Button)sender).BackColor = _activeColor;
}
It clears out the button who previously had _activeColor and sets the color to the current one.
This is pretty common approach to what (I believe) you need. Try to understand this code before trying it, it's relying on Linq.

Related

enable only 1 button in a list?(unity3D)

I have a code which spawns a button(gameobject) with presets everytime I press save.
This button is then saved into a List of gameobjects which I then use to select or deselect them.
I tried to make it so that only 1 button in the list can be selected at a time.
It's working to some degree as If i press the button before the current selected one it works. But if i press any button after the currently selected one it is unable to deselect it.
Can anyone help me with this?
public List<GameObject> presetButtons = new List<GameObject>() ;
This is the list of Buttons
void Update () {
for (int i = 0; i < presetButtons.Count; i++) {
if(presetButtons[i].GetComponent<CamUIButtonHandler>().isSelected){
indicator = i;
topView.isSelected = false;
}
}
for (int u = 0; u < presetButtons.Count; u++) {
if(u != indicator)
presetButtons[u].GetComponent<CamUIButtonHandler>().isSelected = false;
}
}
This is supposed to deactivate the other buttons once 1 is selected.
I'm guessing that there is something that causes it to not be able to overwrite the currently selected button however I can't seem to find the issue.
Can anyone help me with this? much thanks
This sounds to me like a good place to use UGUI's Toggle And ToggleGroup features. Put a toggle component on each button. Then set each of those buttons' group properties to be the same ToggleGroup. Of course if you aren't using UGUI then this won't be possible.

ObjectListView editing doesn't work

I'm trying to create a simple listbox with ObjectListView (WinForm, C#). The goal is to have a single value (a double) and a check box.
I want to be able to edit the double value by Single Click, so here are the relevant lines of code from my MyWindow.Designer.cs file (i've left out the default values for efficiency):
this.olvDepths = new BrightIdeasSoftware.ObjectListView();
this.olvColumn1 = ((BrightIdeasSoftware.OLVColumn)(new BrightIdeasSoftware.OLVColumn()));
...
this.olvDepths.CellEditActivation = BrightIdeasSoftware.ObjectListView.CellEditActivateMode.SingleClick;
this.olvDepths.CheckBoxes = true;
this.olvDepths.CheckedAspectName = "IsDefault";
this.olvDepths.FullRowSelect = true;
//
// olvColumn1
//
this.olvColumn1.AspectName = "Depth";
this.olvColumn1.Text = "";
this.olvColumn1.IsEditable = true;
I then create a list of my class (ShieldingEntry) and use the olvDepths.SetObjects() with the list. My ShieldingEntry class looks like this:
public class ShieldingEntry
{
public double Depth { get; set; }
public bool IsDefault { get; set; }
}
However, when I click the field, it doesn't go into edit mode. I've also tried the DoubleClick, SingleClickAlways, and F2Only modes and they don't work either.
The Checkbox works fine.
************** I have additional information *********************
I've pulled and build the ObjectListView source, so I could step through it.
I put a breakpoint in the OLV StartCellEdit method and it gets called and appears to setup and select the control appropriately. It just never appears...
As I noted in the comments on the answer below, I've got this control on a tabbed dialog, and if I switch to another tab, then back, the control works fine.
What am I missing?
I've used ObjectListView before, and here is what I had to do:
Handle the CellEditStarting event. This event is raised when the cell goes into edit mode. Since OLV doesn't really have built-in editors, you have to make your own. Then handle the CellEditFinishing event to validate the data before putting it back into your model.
So first, handling the CellEditStarting event:
private void objlv_CellEditStarting(object sender, CellEditEventArgs e)
{
//e.Column.AspectName gives the model column name of the editing column
if (e.Column.AspectName == "DoubleValue")
{
NumericUpDown nud = new NumericUpDown();
nud.MinValue = 0.0;
nud.MaxValue = 1000.0;
nud.Value = (double)e.Value;
e.Control = nud;
}
}
This creates your editing control. If you want to make sure the size is right, you can set the size of the control (in this case a NumericUpDown) to the cell bounds using e.CellBounds from the event object.
This will show the editor when you click in the cell. Then you can handle the editor finished event to validate the data:
private void objlv_CellEditFinishing(object sender, CellEditEventArgs e)
{
if (e.Column.AspectName == "DoubleValue")
{
//Here you can verify data, if the data is wrong, call
if ((double)e.NewValue > 10000.0)
e.Cancel = true;
}
}
I don't think handling it is required, but its good practice to validate data from the user.
The editing control in the CellEditStarting event can be any control, even a user defined one. I've used a lot of user defined controls (like textboxes with browse buttons) in the cell editor.
[Edit]
I uploaded an example here dropbox link that seems to work. Might not be in the exact view as needed, but seems to do the job.
For anyone else with this problem. I had it specifically when trying to edit a 'null' value in a decimal? on the OLV on a tab page. Solution for me was to set UseCustomSelectionColors to 'False'. I didn't look elsewhere to see if it was reported as a bug. Seems like a bug.

Identifying indexes in an array that haven't been used

OK so I have created an array of four buttons, when one of the buttons is clicked the background colour will change and the value of that button will be stored in a variable. however, if another button is clicked then I want the button that was clicked originally to revert back to the background colour it was originally, while the new button will change its background colour. I.e. only one button at a time will be 'selected'. at the minute i have this:
btn[0].BackColor = Color.DimGray;
btn[1].BackColor = Color.DimGray;
btn[2].BackColor = Color.DimGray;
btn[3].BackColor = Color.DimGray;
btn[selectedIndex].BackColor = Color.Lime;
I was wondering if there is a way for me to isolate the Indexes that aren't selected and setting them all back to the same colour without having to repaeat the same line of code multiple times, i only ask because there are 17 more buttons on the interface and it just looks horrible.
You can set them all in a single for loop, like this:
for (var i = 0 ; i != btn.Length ; i++) {
btn[i].BackColor = (i == selectedIndex)
? Color.Lime
: Color.DimGray;
}
The conditional inside the loop compares i, the current index, to selectedIndex, and determines if the button's background is to be set to lime or dim gray.

C# ComboBox disable highlighting

I have custom ComboBox, where DropDownStyle = ComboBoxStyle.DropDown;.DropDown style is set because I want to set the Text property of the ComboBox to something outside the list of values. Everything works good, except that ComboBox is highlighting the text when it's left and when I click on the combobox editing is avaible. How can I cope with this?
To illustrate:
First Picture is where everything looks good, second is the highlight situation, third editing is on.
Try un-selecting the text after the DropDown closes:
void comboBox1_DropDownClosed(object sender, EventArgs e) {
this.BeginInvoke(new Action(() => { comboBox1.Select(0, 0); }));
}
If you are referring to disabling the highlighting and editing, then you might want to consider setting the DropdownStyle property to DropdownList.
yourComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
Tricky problem to solve. It seems to be from the Resize event. There are a lot of solutions that do something similar to this, but none that I've seen worked for me until I tried this. (This is a solution that does not require inheritance from ComboBox; inheriting is probably a much more straight forward solution, but requires you to always use your inherited class and never the actual ComboBox class.)
comboBox.Resize += (s, e) => {
if (!comboBox.IsHandleCreated)
return; // avoid possible exception
comboBox.BeginInvoke(new Action(() => comboBox.SelectionLength = 0));
};
Set the selection length to zero to get rid of the highlight, but when? Other examples do it in other places, but the problem seems to be specifically caused by Resize, so doing it after Resize fixes it consistently, at least for me. (Can still see it flicker when you resize the window though, but it always ends up ok.)
BeginInvoke ensures that it happens sufficiently after Resize to work, and the check for IsHandleCreated prevents it from being called before the handle is created, in which case BeginInvoke would throw an exception.
This slightly more complex version includes some checks to prevent a focused control from losing highlight, since it actually should have it. It also doesn't fire if the parent doesn't exist yet, or if the parent does not have an active control yet, both signs that things are too early.
comboBox.Resize += (s, e) => {
if (!comboBox.IsHandleCreated)
return;
comboBox.BeginInvoke(new Action(() => {
var parent = comboBox.FindForm();
if (parent == null)
return;
if (parent.ActiveControl == null)
return;
if (parent.ActiveControl == comboBox)
return;
comboBox.SelectionLength = 0;
}));
};
I tried to make a version that would 'preserve' the selection length rather than always set it to zero, but I couldn't get it to synchronize properly. Many Resize events can fire before the BeginInvoke delegates start to fire, so the preserved value will always be overwritten by the broken one. I tried saving them all in a Queue or Stack, but in both cases, I was unable to reverse the ordering (not really sure why, since that makes no sense).
To solve the same I have tried almost EVERYTHING:
setting the DropdownStyle property to DropdownList
this.BeginInvoke(new Action(() => { comboBox1.Select(0, 0); }));
combobox1.SelectionLength = 0;
changing comboBox.TabIndex
Not tried SendKeys.Send("{ESC}"); because it is not a reliable solution
Nothing helped.
The only stable and working solution was to move a focus on another Label control:
label.Focus();
You could also hide that label.
I know this post is old but recently I have the same problem with combobox.
Situation : I have an editable combobox which propose complete words when user write some letters.
But when I want to type a letter, combobox auto highlight the text and the next letter auto replace the previous.
Solution : I use a textbox to avoid any highlight like that:
<ComboBox IsTextSearchEnabled="False" IsEditable="True" x:Name="CMB_ClientName"/>
<TextBox Text="{Binding ElementName=CMB_ClientName, Path=Text}" TextChanged="ComboBoxChange" x:Name="TXT_ClientName"/>
And I generate the textbox TextChanged event :
private void ComboBoxChange(object sender, TextChangedEventArgs e)
{
//Clear ComboBox items
CMB_ClientName.Items.Clear();
//Auto Open DropDownList
CMB_ClientName.IsDropDownOpen = true;
//Get data from database (use entity framework 6.x)
dbEntity.Client.Load();
//Attribute Data to variable
var clients = dbEntity.Client.Local;
foreach (Client client in clients)
{
//If data begin with the texbox text, the data is add to the combobox items list.
if (client.Nom.ToLower().StartsWith(TXT_NomClient.Text.ToLower()))
{
CMB_ClientName.Items.Add(client.Nom);
}
}
}
I know this solution isn't realy beautifull, but it is for me the easiest solution to avoid highlight text and all the solutions in this post don't work for me.
I hope this solution will be helpfull, thanks for reading.
Math.
Ps: My apologies, my English is not very good. I hope you will understand me correctly.
Nothing worked for me ( I want the form to load with no highlighting in any combobox) until I set the combobox property TabStop to false. This meant that one of my buttons took the tab highlight which I didn't like so I set them all to false for start up and adjusted them programatically as needed.
I know this is an old thread, but my solution is similar to that of the others, but relies on the Form.ResizeEnd event. In its event handler, I iterate through the ComboBoxes and set ComboBox.SelectionLength to 0.
private void Form_ResizeEnd(object sender, EventArgs e)
{
foreach(ComboBox comboBox in parentControl.Controls.OfType<ComboBox>
{
comboBox.SelectionLength = 0;
}
}
This is what worked for me:
Set DrawMode to OwnerDrawFixed
Set cbxSubsystems.DrawItem event to the function below
private void cbxSubsystems_DrawItem(object sender, DrawItemEventArgs e)
{
Color BgClr;
Color TxClr;
if( (e.State & DrawItemState.ComboBoxEdit) == DrawItemState.ComboBoxEdit )
{
// Do not highlight main display
BgClr = cbxSubsystems.BackColor;
TxClr = cbxSubsystems.ForeColor;
}
else
{
BgClr = e.BackColor;
TxClr = e.ForeColor;
}
e.Graphics.FillRectangle(new SolidBrush(BgClr), e.Bounds);
TextRenderer.DrawText(e.Graphics, cbxSubsystems.Items[e.Index].ToString(), e.Font, e.Bounds,
TxClr, BgClr, TextFormatFlags.Left | TextFormatFlags.VerticalCenter );
}

How to Update Frequency of clicked button

Hi I am writing some code for my homework and I am stuck. I created one general click event handler for digit Buttons:
private void btnN_Click(object sender, EventArgs e),
and now I need to make frequency Array which I need to update every time when one of the button is clicked.
Here is freqArray:
private int[] freqArray = new int[10];
How can I do that if there is let say nine buttons?
Thank you
lastNum is number of buttons.
private void btnN_Click(object sender, EventArgs e)
{
for (int i = 0; i < lastNum; i++)
{
freqArray[i]++;
lstFrequencies.Items[i] = i + "\t\t" + freqArray[i];
}
}
Gosh, this is getting out of hand.. but since the original idea of giving hints and helping you along the way has hit the wall - I'll discuss the problem and will leave the decision to you..
The core problem is to identify within the common click event just which of the many buttons has been clicked. The key to this is usually in the event's parameters; in this case the sender is the button that got clicked.
We will look at three different ways to identify the sender:
By comparing it to the Control
By looking at its Name
By using an index stored in its Tag
So the simplest and most direct approach would be something like this:
if (sender == button1) freqArray[0]++;
else if (sender == button2) freqArray[1]++;
..
Note that while the designer names the controls you add with a count from 1 the programmers count from 0! (As do many data structures in C# including your array of counts!)
There are other approaches and since we are doing a little lesson here we go:
Sender is of the most basic type object; you can cast an object to its actual Type like this:
Button b = (Button) sender;
And now you can access all the button's properties, including the Name. So you could write the above code like this:
if (b.Name == "button1") freqArray[0]++;
else if (b.Name == "button2") freqArray[1]++;
..
This has un-coupled the actual button control from the identification and replaced it by a string.
And there is a general purpose property called Tag, which incidentally is also of class object; you can store anything in it. This makes it sometimes quite valuable and often one creates a special structure or even class just to store many things in a Tag..
So if you have created the Buttons to have their Tag contain an index you could use that:
freqArray[ (int) ( (Button) sender).Tag) ]++;
Note the double casts and all those parenthesis! It looks complicated and it is. It is just one line instead of the long vector of if clauses we saw before. But it only works if you have set the Tags before, maybe in the load event:
button1.Tag = 0;
button2.Tag = 1;
button3.Tag = 2;
...
So you have to invest first and can harvest later..
A lot to digest here.. Your pick!
One thing you must understand is you shouldn't ask for approach to a problem. However since your question requires it.
First you should add Tags to the buttons to differentiate them:
button1.Tag = "1";
button2.Tag = "2";
.
.
.
Then in your event handler cast the sender object to your control type:
Button a = (button)sender;
Then check the tag of the button a to add frequencies:
freqArray[Convert.ToString(a.Tag)-48] = freqArray[Convert.ToString(a.Tag)-48] + 1;

Categories

Resources