I'm creating a Connect 4 game. However I'm stuck on clicking on the button and it will generate the x,y coordinates. Example: press button 1 - generates x:1 y:2 etc.
This is my code so far:
private void button1_Click(object sender, EventArgs e)
{
Output_textBox.AppendText("You have inserted in Column 1");
Output_textBox.AppendText(Environment.NewLine);
TextBox[] boxes = { textBox11, textBox12, textBox13, textBox14, textBox15, textBox16 };
if (currentState == Gamestate.Player1Turn)
{
if (boxes[counter].BackColor != SystemColors.HotTrack && boxes[counter].BackColor != Color.Red)
{
boxes[counter].BackColor = SystemColors.HotTrack;
return;
}
counter = counter + 1;
}
else if (currentState == Gamestate.Player2Turn)
{
if(boxes[counter].BackColor != SystemColors.HotTrack && boxes[counter].BackColor != Color.Red)
{
boxes[counter].BackColor = Color.Red;
// m_Connect4GameLogic.PlayerPlayed(player_enum, 1, 3);
return;
}
counter = counter + 1;
}
}
The comment bit is what someone advised me to write a similar code to it. However I don't really know how to use enums.
How do you use enums, and how would you the implement "click button1 (generates the x,y co-ordinates) and the button will pass information to the game logic "?
Related
For a school project I need to develop a platform style game purely in C# Windows forms and cannot use any other languages. I have a gravity and movement system sorted already but my character is still able to jump off the map or jump through picture boxes. How would I go about making these objects solid so that the character cannot run through them. Here is my code
What my game looks like:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool left;
bool right;
int gravity = 20;
int force;
bool jump;
private void Timer(object sender, EventArgs e)
{
if (left == true)
{
Character.Left -= 15;
if (Character.Image != Properties.Resources.LeftChar)
{
Character.Image = Properties.Resources.LeftChar;
}
}
if (right == true)
{
Character.Left += 15;
if (Character.Image != Properties.Resources.RightChar)
{
Character.Image = Properties.Resources.RightChar;
}
}
if (jump == true)
{
Character.Top -= force;
force -= 1;
}
if (Character.Top + Character.Height >= GameBoundary.Height)
{
Character.Top = GameBoundary.Height - Character.Height;
jump = false;
}
else
{
Character.Top += 10;
}
}
private void keydown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.A)
left = true;
if (e.KeyCode == Keys.D)
right = true;
if (jump != true)
{
if (e.KeyCode == Keys.W)
{
jump = true;
force = gravity;
}
}
}
private void keyup(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.A)
left = false;
if (e.KeyCode == Keys.D)
right = false;
}
}
I created an invisible panel that was the same size of the game called "Gameboundary", this made it possible for the player to walk on the bottom of the window, but I am not sure how I would apply this to the rest of the code. If anybody has any suggestions it will be greatly welcome. Not too good at C# just yet!
Here is a basic Collision Detection system:
public class CollisionDetection
{
public static bool ObjectTouchingOthers(Control Object, int SpaceBetweenObjects)
{
for (int i = 0; i < Object.Parent.Controls.Count; i++)
{
if (Object.Parent.Controls[i].Name != Object.Name)
{
if (Object.Left + Object.Width + SpaceBetweenObjects > Object.Parent.Controls[i].Left && Object.Top + Object.Height + SpaceBetweenObjects > Object.Parent.Controls[i].Top && Object.Left < Object.Parent.Controls[i].Left + Object.Parent.Controls[i].Width + SpaceBetweenObjects && Object.Top < Object.Parent.Controls[i].Top + Object.Parent.Controls[i].Height + SpaceBetweenObjects)
{
return true;
}
}
}
return false;
}
public static bool ObjectTouchingOthers(Control Object, int SpaceBetweenObjects, Control[] ControlsToExclude )
{
for (int i = 0; i < Object.Parent.Controls.Count; i++)
{
if (ControlsToExclude.Contains(Object.Parent.Controls[i]) == false && Object.Parent.Controls[i].Name != Object.Name)
{
if (Object.Left + Object.Width + SpaceBetweenObjects > Object.Parent.Controls[i].Left && Object.Top + Object.Height + SpaceBetweenObjects > Object.Parent.Controls[i].Top && Object.Left < Object.Parent.Controls[i].Left + Object.Parent.Controls[i].Width + SpaceBetweenObjects && Object.Top < Object.Parent.Controls[i].Top + Object.Parent.Controls[i].Height + SpaceBetweenObjects)
{
return true;
}
}
}
return false;
}
}
The first argument Object is the control you want collision detection for, and it will only detect other controls in the same container, so if you used it for a control in a panel, for example, it would only work with other controls in the panel, likewise with a Form or any other control. The second argument simply specifies how much distance you want between the controls when they are touching. If you're using the second overload, the third argument is an array of controls that you do not want collision detection for. This is how you would use the second overload:
private void btnMoveLeft_Click(object sender, EventArgs e)
{
btnPlayer.Left -= 1;
if (CollisionDetection.ObjectTouchingOthers(btnPlayer, 1, new Control[] {button1, button2}) == true)
{
btnPlayer.Left += 1;
}
}
With this overload, it will continue right through the controls you specified in the array.
And just to wrap it up, here's a basic example of how to set up collision detection:
private void btnMoveLeft_Click(object sender, EventArgs e)
{
btnPlayer.Left -= 1;
if (CollisionDetection.ObjectTouchingOthers(btnPlayer, 1) == true)
{
btnPlayer.Left += 1;
}
}
private void btnMoveRight_Click(object sender, EventArgs e)
{
btnPlayer.Left += 1;
if (CollisionDetection.ObjectTouchingOthers(btnPlayer, 1) == true)
{
btnPlayer.Left -= 1;
}
}
private void btnMoveUp_Click(object sender, EventArgs e)
{
btnPlayer.Top -= 1;
if (CollisionDetection.ObjectTouchingOthers(btnPlayer, 1) == true)
{
btnPlayer.Top += 1;
}
}
private void btnMoveDown_Click(object sender, EventArgs e)
{
btnPlayer.Top += 1;
if (CollisionDetection.ObjectTouchingOthers(btnPlayer, 1) == true)
{
btnPlayer.Top -= 1;
}
}
Just remember that you're going to have to change the names of the controls in the code I have here. And for reference, here is my test form:
You need to implement collision detection. Draw an imaginary box around your person and any objects you don't want him to pass through. Check if any of the boxes overlap. If they do, move one or both of the objects back until the boxes no longer overlap.
Picture boxes has a .Bounds with a .IntersectWith and this will take an object of type Rectangle.
In a game, you will typically have an ongoing timer, checking all sorts of stuff and progressing time.
In this timer i would make a:
if (pictureBox1.Bounds.IntersectsWith(pictureBox2.Bounds))
{
//They have collided
}
You might have a lot of objects, so you could make a List<PictureBox> and add those objects, then the list will have refferences to those PictureBoxes, that means that they will automatically be updated with the right bounds, when you go through the List.
Be sure to make the List a public property of your form class. Then before rolling through the List, instead set another List = to the public object List. This ensures that you can do a foreach() loop without getting exceptions.
I need help to get my listbox.selecteditem to work.
This is my pseudo code.
public Form1()
{
if (x == 1)
{
if (this.ListBox1.SelectedIndex != 5 ||
this.ListBox1.SelectedIndex != -1)
{
ListBox1.MouseDoubleClick += new MouseControlHandler(ListBox1_MouseDoubleClick);
}
}
else
{
//Do something else.
}
}
private void ListBox1_MouseDoubleClick(object sender, System.EventArgs e)
{
int index = this.ListBox1.IndexFromPoint(e.Location);
if (index != System.Windows.Forms.ListBox.NoMatches)
{
MessageBox.Show("Hello World!");
}
}
Now I have gotten the condition to check when x is not 1; the double click does not work, which is what I wanted.
When x is 1; I have 10 items added to the listbox. I don't want the user to see the "Hello World!" message when the user clicks on the item with index =5.
I can't get this to work. Even when the user clicks on item with index = 5; the message still pops up. I tried debugging but the main pop up screen does not open during debugging. All I could see is selectedindex = -1. The real code is huge.
Is this the right approach to do this? Thanks.
The issue is you are using || (OR) when you should use && (AND).
Let's break it down: when index = 5, you don't want anything to happen. But when index = 5, then index != -1 is True and so the double click code is still triggered because False OR True = True. In addition, when x != 1, you need to unsubscribe from the event (or set it to null). If not, once it's set, it would be triggered if there is a double click event.
This is the code you want:
public Form1()
{
if (x == 1 && this.ListBox1.SelectedIndex != 5 && this.ListBox1.SelectedIndex != -1)
{
ListBox1.MouseDoubleClick += new MouseControlHandler(ListBox1_MouseDoubleClick);
else
{
ListBox1.MouseDoubleClick = null;
}
}
private void ListBox1_MouseDoubleClick(object sender, System.EventArgs e)
{
int index = this.ListBox1.IndexFromPoint(e.Location);
if (index != System.Windows.Forms.ListBox.NoMatches)
{
MessageBox.Show("Hello World!");
}
}
What I am trying to do is simple (I cannot figure it out of course). I am making a sample shop with an inventory system in Winform App format where if on the customer side the "Place Order" button is clicked it deducts from inventory; the amount deducted depends on the quantity of the item ordered. Anyway with this code,
private void button7_Click(object sender, EventArgs e)
button7.Enabled = true;
//Read in value
int qty = Convert.ToInt32(nudQuantity.Value);
if ((rdoSmallCup.Checked & rdoStraw.Checked) == true) {
//Removing four from inventory for strawberry after an order is made
InvStrawberry = InvStrawberry - (4 * qty);
if (InvStrawberry <= 0) {
button7.Enabled = false;
} else {
button7.Enabled = true;
}
label17.Text = Convert.ToString(InvStrawberry);
I am seeing that while it does compile with no errors once the inventory for strawberry has fallen past zero (it will actually be a negative value which I do not want but is another question for another time) the Place Order button ("Button 7") will be grayed out and unusable which is the goal but once inventory is added again this button is still unusable. Can someone explain how I can have this button re-enabled (even though I said it in the 'else' condition)?
Ron and Heretic's comments are right. You cannot access the code in Button7 click event handler once it has been 'disabled'. The only way to enable it again is from outside logic, say after you added additional items into the inventory, you can enable the button right after that.
Also you can can be simplify a bit:
private void button7_Click(object sender, EventArgs e)
//Read in value
int qty = Convert.ToInt32(nudQuantity.Value);
if ((rdoSmallCup.Checked & rdoStraw.Checked) == true) {
//Removing four from inventory for strawberry after an order is made
InvStrawberry = InvStrawberry - (4 * qty);
if (InvStrawberry <= 0)
button7.Enabled = false;
label17.Text = Convert.ToString(InvStrawberry);
...
This code will allow an infinite number of subtraction. Hence, you will need a control that will stop the subtraction when you go below zero.
private void button7_Click(object sender, EventArgs e){
// I have no idea why you have enabled the button here, mate
//Converting the quantity
int qty = Convert.ToInt32(nudQuantity.Value);
if((roSmallCup.Checked & rdoStraw.Checked) == true) {
//triggers when the Inventory of strawberry is more than zero
if( (InvStrawberry - (4 * qty)) > 0 ){
InvStrawberry = InvStrawberry - (4 * qty);
} else
{
button7.ENabled = false;
MessageBox.Show("We are out of inventory,Sorry!");
}
label17.Text = Convert.ToString(InvStrawberry);
}
}
If you want the button to possibly update every time that you change the value of InvStrawberry then the best option is to make a property for InvStrawberry and update the status of the button there. That cuts down the logic that you need to use right throughout your code.
Try this:
public class StrawberryForm : Form
{
private int _invStrawberry = 0;
private int InvStrawberry
{
get
{
return _invStrawberry;
}
set
{
_invStrawberry = value;
button7.Enabled = _invStrawberry > 0;
}
}
private void button7_Click(object sender, EventArgs e)
{
int qty = Convert.ToInt32(nudQuantity.Value);
if ((rdoSmallCup.Checked & rdoStraw.Checked) == true)
{
this.InvStrawberry -= 4 * qty;
label17.Text = Convert.ToString(this.InvStrawberry);
}
}
}
you need to move this:
if (InvStrawberry <= 0) {
button7.Enabled = false;
} else {
button7.Enabled = true;
}
to an Updae method or loop that will check it regularly, right now its in your click, and therefore will never get called to enable it again once it is disabled, since at that point you cant click on it.
also, say you have two variables, numberStrawberries representing youre remaining inventory, and lot representing the four strawberries you put in a purchase...
if(numberStrawberries >= lot){
//we have strawberries, and more at least 4 or more
numberStrawberries-=lot;
}else if(numberStrawberries!=0 && numberStrawberries < lot){
//we have strawberries but only (remaining)
//how many were short(how many we have is still in numberStrawberries)
int short = lot- numberStrawberries;
numberStrawberries=0;
}else{
//all out of strawberries
}
I have a setting in my application that requires any value between 24 and 65520 that must be evenly divisible by 24. I decided to implement this with a horizontal scrollbar and a textbox that shows the current value of the scrollbar, and can have a value manually typed into it (which then sets the scrollbar value). The scrollbar has minimum = 24, maximum = 65520, small & large increments = 1. The default value at app launch is 960. I ended up having to use a couple of event handlers for both the textbox and the scrollbar, and even still it didn't work perfectly. My first mostly-working attempt was this:
private void hScrollBar_TicksPerQuarter_Scroll(object sender, ScrollEventArgs e)
{
int NewValue = e.NewValue;
if (e.Type != ScrollEventType.EndScroll)
{
if (e.NewValue < e.OldValue)
{
NewValue = e.NewValue - (e.NewValue % 24);
}
else if (e.NewValue > e.OldValue)
{
NewValue = e.NewValue + (e.NewValue % 24 == 0 ? 0 : 24 - (e.NewValue % 24));
}
txtTicksPerQuarter.Text = NewValue.ToString();
}
else
{
hScrollBar_TicksPerQuarter.Value = NewValue;
}
}
private void hScrollBar_TicksPerQuarter_ValueChanged(object sender, EventArgs e)
{
if (hScrollBar_TicksPerQuarter.Value.ToString() != txtTicksPerQuarter.Text)
{
hScrollBar_TicksPerQuarter.Value = Convert.ToInt32(txtTicksPerQuarter.Text);
}
}
private void txtTicksPerQuarter_Leave(object sender, EventArgs e)
{
TrySetTicksPerQuarter();
}
private void txtTicksPerQuarter_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
TrySetTicksPerQuarter();
}
private void TrySetTicksPerQuarter()
{
bool useOldValue = false;
int TicksPerQuarter_OldValue = hScrollBar_TicksPerQuarter.Value;
int TicksPerQuarter = 0;
if (Int32.TryParse(txtTicksPerQuarter.Text, out TicksPerQuarter))
{
if (TicksPerQuarter % 24 == 0)
{
hScrollBar_TicksPerQuarter.Value = TicksPerQuarter;
}
else
{
useOldValue = true;
MessageBox.Show("Must enter a value that is a multiple of 24, with a minimum of 24 and a maximum of 65520.", "Invalid TicksPerQuarter", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
else
{
useOldValue = true;
}
if (useOldValue)
txtTicksPerQuarter.Text = TicksPerQuarter_OldValue.ToString();
}
This works fairly well, if I enter a value in the textbox and leave the box or press Enter, it will update the scrollbar accordingly, and if the value is not a proper multiple of 24 it will just reset itself to the last valid value and display a message to the user indicating the issue. Scrolling the scrollbar updates the textbox in real time as you scroll, and everything basically works. The problem is that when you click and drag the scrollbar, the moment you let results in a jump in the value (usually of a couple hundred or so, in either direction). Not sure why it was happening, I started experimenting with changes the "Scroll" event on the scrollbar to see if I could fix it, so releasing the scrollbar after dragging it would result in the value staying what it displayed at the time you release it. It took a lot of experimentation, including some drastic overhauls to everything that didn't even work as well as the code I put above, but ultimately the best I could get was to keep all the code above the same in the other events, and just change the Scroll event to this:
ScrollEventType[] IncrementScrollEvents = new ScrollEventType[] { ScrollEventType.LargeIncrement, ScrollEventType.SmallIncrement, ScrollEventType.Last };
ScrollEventType[] DecrementScrollEvents = new ScrollEventType[] { ScrollEventType.LargeDecrement, ScrollEventType.SmallDecrement, ScrollEventType.First };
private void hScrollBar_TicksPerQuarter_Scroll(object sender, ScrollEventArgs e)
{
int NewValue = e.NewValue;
if (IncrementScrollEvents.Contains(e.Type))
{
NewValue = e.NewValue + (e.NewValue % 24 == 0 ? 0 : 24 - (e.NewValue % 24));
}
else if (DecrementScrollEvents.Contains(e.Type))
{
NewValue = e.NewValue - (e.NewValue % 24);
}
else if (e.Type == ScrollEventType.ThumbTrack)
{
if (e.NewValue < e.OldValue)
{
NewValue = e.NewValue - (e.NewValue % 24);
}
else if (e.NewValue > e.OldValue)
{
NewValue = e.NewValue + (e.NewValue % 24 == 0 ? 0 : 24 - (e.NewValue % 24));
}
}
else if (e.Type == ScrollEventType.EndScroll)
{
hScrollBar_TicksPerQuarter.Value = NewValue;
}
else
{
return;
}
txtTicksPerQuarter.Text = NewValue.ToString();
}
This definitely works better, and if I had to estimate it, I'd say maybe 4 out of 5 times you release the scrollbar, the value remains where it was at the last moment before you let go of the mouse button. But it still isn't perfect.
I was hoping there is a better way to do this, both in terms of functionality being just that little bit more perfect than it is now, and perhaps even in terms of the overall complexity of the code. I didn't expect to have to write code in 4 different events across 2 controls to do this, but perhaps there isn't a better way after all?
EDIT 1:
I had an idea to use increments of 1 and min/max 1-2730 instead of 24-65520 and then instead of doing math and verification and manually setting the value of the scrollbar to ensure it's a multiple of 24, I will instead just multiply its real value by 24 to get the usable value and the display value for the textbox. This code is now identical in functionality to what I had above, with a lot less complexity. I also moved the warning messagebox for invalid entry in the textbox so that it displays a message even when the user types something that can't even be converted to an integer:
private void hScrollBar_TicksPerQuarter_Scroll(object sender, ScrollEventArgs e)
{
txtTicksPerQuarter.Text = (e.NewValue * 24).ToString();
}
private void txtTicksPerQuarter_Leave(object sender, EventArgs e)
{
TrySetTicksPerQuarter();
}
private void txtTicksPerQuarter_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
TrySetTicksPerQuarter();
}
private void TrySetTicksPerQuarter()
{
bool useOldValue = false;
int TicksPerQuarter_OldValue = hScrollBar_TicksPerQuarter.Value;
int TicksPerQuarter = 0;
if (Int32.TryParse(txtTicksPerQuarter.Text, out TicksPerQuarter))
{
if (TicksPerQuarter % 24 == 0)
{
hScrollBar_TicksPerQuarter.Value = (TicksPerQuarter / 24);
}
else
{
useOldValue = true;
}
}
else
{
useOldValue = true;
}
if (useOldValue)
{
MessageBox.Show("Must enter a value that is a multiple of 24, with a minimum of 24 and a maximum of 65520.", "Invalid TicksPerQuarter", MessageBoxButtons.OK, MessageBoxIcon.Warning);
txtTicksPerQuarter.Text = (TicksPerQuarter_OldValue * 24).ToString();
}
}
The scrollbar still jumps occasionally when you let go of the mouse button when you're dragging it left and right. I still don't have a solution for that particular problem, unless it's really not something that I can fix due to the way the mouse and scroll bar play with each other?
I just made a small WinForms demo app using just a single scrollbar (hScrollbar1) and a label (Label1).
Created the form's Load event handler and added the following code:
hScrollBar1.Minimum = 1;
hScrollBar1.Maximum = 65520 / 24;
hScrollBar1.Value = 960 / 24;
hScrollBar1.LargeChange = 1;
Created hScrollBar1's ValueChanged event handler and added the following code:
label1.Text = (hScrollBar1.Value * 24).ToString();
Seems to work fine for me this way. Not sure if I could get it to work when using stepping values of 24 in the scrollbar property settings... Sorry for that...
Edit: Just saw your own comment. I agree. :)
IDE: Visual Studio c#, Winforms Application.
I have invested around 12 hours but didn't get success. As DataGridView don't provide radiobutton type of cell. so i am trying to use checkbox cell as radio-buttion functionality.
i.e I want to be checked only one checkbox in a column.
see image:
It looks very simple thing but trust me it is not as simple as we are thinking. before giving reply please test the code.
Here are my sample tested code which i have tried:
code 1
////start
if (e.RowIndex != -1)
{
if (dataGridView1.Rows[e.RowIndex].Cells[0].Value != null && dataGridView1.CurrentCell.ColumnIndex == 0) //null check
{
if (e.ColumnIndex == 0)
{
if (((bool)dataGridView1.Rows[e.RowIndex].Cells[0].Value == true))
{
for (int k = 0; k <= 4; k++)
{
//uncheck all other checkboxes but keep the current as checked
if (k == dataGridView1.CurrentRow.Index)
{
dataGridView1.Rows[k].Cells[0].Value = false;
}
//if (gvTeam1.Rows[k].Cells[2].Selected != null)
//if(k !=e.RowIndex)
}
// gvTeam1.Rows[e.RowIndex].Cells[2].Value = false; // keep the current captain box checked
}
}
//}
// gvTeam1.Rows[rowPointerTeam1].Cells[2].Value = true;
}
}
//end
// here gvTeam1 is Datagridview1
code 2:
tested on datagridview1
private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dataGridView1.CurrentCell.ColumnIndex == 0)
{
for (int i = 0; i < 8; i++)
{
//if (i != dataGridView1.CurrentCell.RowIndex)
dataGridView1.Rows[i].Cells[0].Value = false;
}
dataGridView1.Rows[dataGridView1.CurrentCell.RowIndex].Cells[0].Value = true;
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
//clean al rows
foreach (DataGridViewRow row in dataGridView1.Rows)
{
row.Cells["Select"].Value = false;
}
//check select row
dataGridView1.CurrentRow.Cells["Select"].Value = true;
}
I know I'm late to the party, but here is code to use actual radio buttons instead of checkboxes.
Credit:
Thanks to Arsalan Tamiz's blog post, on which this code is based.
http://arsalantamiz.blogspot.com/2008/09/using-datagridview-checkbox-column-as.html
Also thanks to M. Viper's answer for laying some of the ground work.
Step 1: Add a DataGridView control to your panel and add a CheckBoxColumn (I named mine grid and colRadioButton respectively). I'm not sure if this matters, but the EditMode property of my DataGridView is set to EditOnEnter.
Step 2: Create an event handler for the CellPainting event.
private void grid_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == colRadioButton.Index && e.RowIndex >= 0)
{
e.PaintBackground(e.ClipBounds, true);
// TODO: The radio button flickers on mouse over.
// I tried setting DoubleBuffered on the parent panel, but the flickering persists.
// If someone figures out how to resolve this, please leave a comment.
Rectangle rectRadioButton = new Rectangle();
// TODO: Would be nice to not use magic numbers here.
rectRadioButton.Width = 14;
rectRadioButton.Height = 14;
rectRadioButton.X = e.CellBounds.X + (e.CellBounds.Width - rectRadioButton.Width) / 2;
rectRadioButton.Y = e.CellBounds.Y + (e.CellBounds.Height - rectRadioButton.Height) / 2;
ButtonState buttonState;
if (e.Value == DBNull.Value || (bool)(e.Value) == false)
{
buttonState = ButtonState.Normal;
}
else
{
buttonState = ButtonState.Checked;
}
ControlPaint.DrawRadioButton(e.Graphics, rectRadioButton, buttonState);
e.Paint(e.ClipBounds, DataGridViewPaintParts.Focus);
e.Handled = true;
}
}
Step 3: Handle the CurrentCellDirtyStateChanged event to uncheck the previous selection. This is basically the same as M. Viper's answer.
private void radioButtonChanged()
{
if (grid.CurrentCell.ColumnIndex == colRadioButton.Index)
{
foreach (DataGridViewRow row in grid.Rows)
{
// Make sure not to uncheck the radio button the user just clicked.
if (row.Index != grid.CurrentCell.RowIndex)
{
row.Cells[colRadioButton.Index].Value = false;
}
}
}
}
private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
radioButtonChanged();
}
Step 4: (Optional) Handle the CellClick event to allow the user to check the radio button by clicking anywhere in the cell rather than only directly on the radio button.
private void grid_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == colRadioButton.Index)
{
DataGridViewCheckBoxCell cell = (DataGridViewCheckBoxCell)grid.Rows[e.RowIndex].Cells[colRadioButton.Index];
cell.Value = true;
radioButtonChanged();
}
}
Try This,
private void dataGridView1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
UpdateCellValue(e.RowIndex);
}
private void UpdateCellValue(int CurrentRowIndex)
{
if (CurrentRowIndex < 0)
return;
dataGridView1.Rows[CurrentRowIndex].Cells[0].Value = true;
dataGridView1.EndEdit();
if (CurrentRowIndex > -1)
{
for (int row = 0; row < dataGridView1.Rows.Count; row++)
{
if (CurrentRowIndex != row)
dataGridView1.Rows[row].Cells[0].Value = false;
}
}
}
Changing the default behavior of a control is undesired. We went through this path in one of my project and results were not fruitful. CheckBox control is used for multi-selection unlike the radio button. I would suggest you to write a custom RadioButtonCell for the DataGridView.
This Build a Custom RadioButton Cell and Column for the DataGridView Control article is nice place to start.
Paste this code on datagridview cellcontentclick and it will work as radio button
int row_index = e.RowIndex;
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
if (row_index != i)
{
dataGridView1.Rows[i].Cells["Column1"].Value = false;
}
}
None of the answers worked for me, so:
private void MyDataGridView_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.RowIndex > -1 && myDataGridView.Columns["MyRadioButtonColumnName"].Index == e.ColumnIndex)
{
int rowsCount = myDataGridView.Rows.Count - (myDataGridView.AllowUserToAddRows ? 1 : 0);
for (int rowIdx = 0; rowIdx < rowsCount; rowIdx++)
{
myDataGridView.Rows[rowIdx].Cells[e.ColumnIndex].Value = rowIdx == e.RowIndex;
}
}
}
private void MyDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex > -1 && myDataGridView.Columns["MyRadioButtonColumnName"].Index == e.ColumnIndex)
{
myDataGridView.CancelEdit();
}
}
private void MyDataGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex > -1 && myDataGridView.Columns["MyRadioButtonColumnName"].Index == e.ColumnIndex)
{
bool isSelected = myDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected;
e.PaintBackground(e.ClipBounds, isSelected);
if (e.RowIndex < myDataGridView.Rows.Count - 1 || myDataGridView.AllowUserToAddRows == false)
{
bool isChecked = Convert.ToBoolean(myDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value) == true;
RadioButtonState state = isChecked ? RadioButtonState.CheckedNormal : RadioButtonState.UncheckedNormal; // using System.Windows.Forms.VisualStyles
RadioButtonRenderer.DrawRadioButton(e.Graphics, new Point(e.CellBounds.X + e.CellBounds.Width / 2 - 6, e.CellBounds.Y + e.CellBounds.Height / 2 - 6), state);
}
e.Handled = true;
}
}