WinForms FlowLayoutPanel alignment problem - c#

When I click on a button in my Floqlayoutpanel they should hide at the place where I clicked on them. But instead they disappear and all the other buttons move.
They should hide at their place
But this is what happens
How I create my Buttons:
private void CreateButton()
{
int buttonIndex = 0;
for (int i = 0; i < 16; i++)
{
Button button = new Button();
button.Name = $"Button_{buttonIndex}";
button.Width = 100;
button.Height = 100;
button.Click += OnButtonClick;
button.BackgroundImage = BackSideImage();
flowLayoutPanel1.Controls.Add(button);
buttonIndex++;
}
}
How I hide my Buttons:
private void CompareCards()
{
if (clickedCards.Count >= 3)
{
if (clickedCards[0].PairIndex == clickedCards[1].PairIndex)
{
clickedCards[0].Button.Hide();
clickedCards[1].Button.Hide();
}
else
{
clickedCards[0].Button.BackgroundImage = BackSideImage();
clickedCards[1].Button.BackgroundImage = BackSideImage();
}
clickedCards.Clear();
}
}

Instead of hiding your button, you can make it invisible like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
for (int x = 0; x < 9; x++)
{
var button = new Button
{
Name = "Test-" + x,
Text = "Test-" + x,
Width = 100,
Height = 100
};
button.Click += OnButtonClick;
flowLayoutPanel1.Controls.Add(button);
}
}
private void OnButtonClick(object sender, EventArgs e)
{
//Instead of this...
//((Button)sender).Hide();
//Do this...
var button = ((Button) sender);
button.FlatStyle = FlatStyle.Flat;
button.FlatAppearance.BorderColor = BackColor;
button.FlatAppearance.MouseOverBackColor = BackColor;
button.FlatAppearance.MouseDownBackColor = BackColor;
button.Text = string.Empty;
button.Enabled = false;
}
}

Related

field with a button in the DataGridView

I have a bounded DataGridView. How can I add a button in one field with data? I will attach a screenshot of how I see it. Do you have any recommendations on this?
it's WinForms and I think that I need to write a custom column type.
I don't think the standard DataGridViewColumn subclasses provide what you're after.
It can be done, though: you will have to create your own custom Control (I guess a TextBox with a Button right next to it), and the appropriateDataGridViewColumn and DataGridViewCell subclasses to host your custom control.
Follow the documentation for further details.
Of course, the alternative would be using third-party, smarter grids.
Create custom column:
class TextAndButtonControl : UserControl
{
private TextBox textbox1;
private Button button1;
public TextAndButtonControl()
{
this.textbox1 = new TextBox();
this.Controls.Add(this.textbox1);
this.button1 = new Button();
this.Controls.Add(this.button1);
this.RenderControl();
this.button1.Click += new EventHandler(button1_Click);
}
void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Hi");
}
public string Text
{
get { return this.textbox1.Text; }
set { this.textbox1.Text = value; }
}
public string ButtonText
{
get { return this.button1.Text; }
set { this.button1.Text = value; }
}
public void RenderControl()
{
this.textbox1.Location = new Point(0, 0);
this.textbox1.Width = 2 * this.Width / 3;
this.textbox1.Height = this.Height;
this.button1.Location = new Point(2 * this.Width / 3, 0);
this.button1.Width = this.Width / 3;
this.button1.Height = this.Height;
}
}
Add the control in the following way
private void Form1_Load(object sender, EventArgs e)
{
TextAndButtonControl bcol = new TextAndButtonControl();
bcol.Text = "Button Column ";
bcol.ButtonText = "Click Me";
bcol.Name = "btnClickMe";
bcol.RenderControl();
dgMainGrid.Controls.Add(bcol);
}
There is a DataGridViewButtonColumn-Type (Or if you just want a single Cell as Button -> DataGridViewButtonCell-Type).
You could create the DataGridButtonColumn and then add it to your DataGridView:
DataGridViewButtonColumn tempBtnColumn = new DataGridViewButtonColumn();
tempBtnColumn.HeaderText = "Button";
tempBtnColumn.Text = "Button-Text";
tempBtnColumn.Name = "Button-Name";
tempBtnColumn.UseColumnTextForButtonValue = true;
Grid.Columns.Add(tempBtnColumn);
//or if you want a specified position for the Grid:
Grid.Columns.Insert(0, tempBtnColumn);
Update
Here is an update, you could give the ButtonCell the Value you want and then read that with CurrentCell.Value (here is a example, hope it's understandable):
private void ButtonCellWithValue()
{
DataGridViewButtonCell dgvbc = new DataGridViewButtonCell();
dgvbc.Value = "1";
DataGridViewRow dgvr = new DataGridViewRow();
dgvr.Cells.Add(dgvbc);
dataGridView1.Rows.Add(dgvr);
dgvbc = new DataGridViewButtonCell();
dgvbc.Value = "2";
dataGridView1.Rows[0].Cells[1] = dgvbc;
GridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);
}
void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (((DataGridView)sender).CurrentCell.Value == "1")
{
MessageBox.Show("Super");
}
else if (((DataGridView)sender).CurrentCell.Value == "2")
{
MessageBox.Show("Better");
}
}
Thank a lot #RavirajPalvankar.
If somebody will need, I will write the code here, because cann't write it to Ravuraj's comment, because it's long:
Use the class as Raviraj write:
class TextAndButtonControl : UserControl
{
private TextBox textbox1;
private Button button1;
public TextAndButtonControl()
{
this.textbox1 = new TextBox();
this.Controls.Add(this.textbox1);
this.button1 = new Button();
this.Controls.Add(this.button1);
this.renderControl();
this.button1.Click += new EventHandler(button1_Click);
}
void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Click! The value is:" + this.Text);
}
public string Text
{
get { return this.textbox1.Text; }
set { this.textbox1.Text = value; }
}
public string ButtonText
{
get { return this.button1.Text; }
set { this.button1.Text = value; }
}
public void renderControl()
{
this.textbox1.Location = new Point(0, 0);
this.textbox1.Width = 2 * this.Width / 3;
this.textbox1.Height = this.Height;
this.button1.Location = new Point(2 * this.Width / 3, 0);
this.button1.Width = this.Width / 3;
this.button1.Height = this.Height;
}
}
then in main Form:
private void Form1_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
dt.Columns.Add("col1");
dt.Columns.Add("col2");
for (int j = 0; j < 20; j++)
{
dt.Rows.Add("col1" + j.ToString(), "col2" + j.ToString());
}
this.dataGridView1.DataSource = dt;
this.dataGridView1.Columns[0].Width = 150;
this.txbtnControl = new TextAndButtonControl();
this.txbtnControl.Visible = false;
this.dataGridView1.Controls.Add(this.txbtnControl);
//Handle the cellbeginEdit event to show the usercontrol in the cell while editing
this.dataGridView1.CellBeginEdit += new DataGridViewCellCancelEventHandler(dataGridView1_CellBeginEdit);
}
TextAndButtonControl txbtnControl;
void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex > -1 && e.RowIndex != this.dataGridView1.NewRowIndex)
{
Rectangle rect = this.dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
this.txbtnControl.Location = rect.Location;
this.txbtnControl.Size = rect.Size;
this.txbtnControl.Text = this.dataGridView1.CurrentCell.Value.ToString();
this.txbtnControl.ButtonText = "...";
this.txbtnControl.renderControl();
this.txbtnControl.Visible = true;
}
}

I can not go to "EventHandler" with double click

When btnAsset is double-clicked, it should go to allButton_Click.
But it only goes in one click. how can I do that?
public void Add(MainForm frm)
{
this.form1 = frm;
for (int i = 0; i < 10; i++)
{
btnAsset[i] = new Button();
btnAsset[i].Tag = i;
btnAsset[i].Name = "Asset-" + i.ToString();
btnAsset[i].Width = 150;
btnAsset[i].Height = 120;
btnAsset[i].Visible = true;
btnAsset[i].BackColor = Color.GreenYellow;
form1.flowLayoutVideo.Controls.Add(btnAsset[i]);
btnAsset[i].DoubleClick += new EventHandler(allButton_Click);
}
}
should go here when double clicked
void allButton_Click(object sender, EventArgs e)
{
Button p = sender as Button;
if (p != null)
{
int i = (int)p.Tag;
MessageBox.Show((i + 1).ToString() + ". seçildi");
}
}
Look what the docs says about it:
By default, the ControlStyles.StandardClick and ControlStyles.StandardDoubleClick style bits are set to false for the Button control, and the DoubleClick event is not raised.
You can change this behaviour by creating your own button class deriving from Button and change the style bits.

Cannot add a method to a button click event C# UWP

I have some problems making the HangMan game to work. Since i got my buttons, i had to make a method that displays the alphabet letters to user. So i have this Guessing method what i want to add to a button click event. So i get this red squiqqly line when i try to add a method to a button. The error is in HangMan_OnLoaded method. Thanks!
public void DisplayTheWord()
{
WrongGuesses = 0;
BitmapImage Hangman2 = new BitmapImage();
Uri URL = new Uri(BaseUri, images[WrongGuesses]);
Hangman2.UriSource = URL;
picture.Source = Hangman2;
string[] ReadWords = File.ReadAllLines("EnglishWords.txt");
int NextNumber = (new Random().Next(words.Length));
copyCurrent = "";
current = words[NextNumber];
for (int i = 0; i < ReadWords[NextNumber].Length; i++)
{
copyCurrent += "_" + " ";
}
CopiedWord.Text = copyCurrent;
}
private void Hangman_OnLoaded()
{
const int btnSize = 35;
var c = 0;
for (var i = 65; i <= 90; i++)
{
var btn = new Button();
btn.Content = (char)i;
btn.Width = btn.Height = btnSize;
var margin = btn.Margin;
margin.Left = c += 37;
btn.Margin = margin;
GridMain.Children.Add(btn);
btn.Click += Guessing();
}
}
private void Guessing(object sender, EventArgs e)
{
for (var i = 65; i <= 90; i++)
{
var btn = new Button();
btn = sender as Button;
btn.Content = (char) i;
var choice = btn.ToString();
if (copyCurrent.Contains(choice))
{
char[] temp = copyCurrent.ToCharArray();
char[] find = current.ToCharArray();
char guessChar = choice.ElementAt(0);
for (int index = 0; index < find.Length; index++)
{
if (find[index]== guessChar)
{
temp[index] = guessChar;
}
}
copyCurrent = new string(temp);
}
else
{
WrongGuesses++;
}
if (WrongGuesses < 6)
{
}
}
}
private void DisplayCopy()
{
CopiedWord.Text = "";
for (int index = 0; index < copyCurrent.Length; index++)
{
CopiedWord.Text += copyCurrent.Substring(index, 1);
CopiedWord.Text += " ";
}
}
You need to remove the brackets from the line:
btn.Click += Guessing();
so that it becomes:
btn.Click += Guessing;
#swatsonpicken said right. you need to remove the brackets from the line:
btn.Click += Guessing();
and replace with:
btn.Click += Guessing;
And one more thing you will need to correct that is the
private void Guessing(object sender, EventArgs e)
Write above line as below:
private void Guessing(object sender, RoutedEventArgs e)
Hope this will help. :)
I think:
The error is because Guessing is void and dont return nothing but yor're using Guessing like a method that return a event:
btn.Click += Guessing();
For dix that return a value event :)
Make sure your handler fits to Event you want to use:
private void Guessing(object sender, RoutedEventArgs e) {
//your handler code
}
btn.Click += Guessing;
Reason for that is, each event is expecting signature of delegate and defines parameters.

Reference a button outside of a loop?

This function dynamically creates nine buttons for use in a game I am making. You can see what attributes I give to the button.
private void createbuttons()
{
int tot = 0;
int x = 100;
int y = 100;
while(tot < 9)
{
string buttonsname = (tot + "button").ToString();
Button creating = new Button();
creating.Name = buttonsname;
creating.Size = new Size(100, 100);
creating.Click += delegate
{
MessageBox.Show("You clicked me!");
};
creating.Text = buttonsname;
if(x > 300)
{
y += 100;
x = 100;
}
creating.Location = new Point(x, y);
Controls.Add(creating);
tot += 1;
x += 100;
}
}
What I want to know is how to reference these buttons in different parts of the same form. Specifically when 'Start Game' is clicked I want to change the text for each button to something different.
private void button10_Click(object sender, EventArgs e)
{
//What would I write here to change the text?
}
You can access the buttons by enumerating the controls, or you could create a list of buttons for future reference, and use that list later.
Here is how you do it with a list:
private IList<Button> addedButtons = new List<Button>();
private void createbuttons() {
int tot = 0;
int x = 100;
int y = 100;
while(tot < 9) {
string buttonsname = (tot + "button").ToString();
Button creating = new Button();
creating.Name = buttonsname;
creating.Size = new Size(100, 100);
creating.Click += delegate {
MessageBox.Show("You clicked me!");
};
creating.Text = buttonsname;
if(x > 300) {
y += 100;
x = 100;
}
creating.Location = new Point(x, y);
addedButtons.Add(creating); // Save the button for future reference
Controls.Add(creating);
tot += 1;
x += 100;
}
}
Now you can do this:
foreach (var btn : addedButtons) {
btn.Text = "Changed "+btn.Text;
}
The form has a property Controls that holds all child controls. To find a child control by its Name property use method Find, which returns the array, because there may be several control with the same Name, but if you make sure that names exist, are unique, and you know their type (Button) you can just take the first item from the array and cast it:
private void button10_Click(object sender, EventArgs e)
{
Button buttonNamedFred = (Button)this.Controls.Find("Fred", false)[0];
buttonNamedFred.Text = "I'm Fred";
}

How to move panels up/down on keysDown event in c#

I've 4 panels, having same Y and different X, that are created at the program start on a picturebox. When I click on a panel, it sets the focus and is ready to get a keysDown event so i.e. if I click on up arrow key the panel moves up.
This is the code:
public partial class FormView : Form
{
List<CircleButton> myPanels = new List<CircleButton>(); // array of panels CircleButton
Point[] arrayPoints_milestones; // array of X,Y
int index;
public FormView()
{
InitializeComponent();
arrayPoints_milestones = new Point[4];
for (int i = 0; i < 4; i++ )
{
arrayPoints_milestones[i] = new Point { X = 20, Y = 20 };
}
test();
}
protected void panel_Click(object sender, EventArgs e)
{
myPanels[index].PreviewKeyDown -= new PreviewKeyDownEventHandler(panel_KeyDown);
CircleButton panel = sender as CircleButton;
index = (int)panel.Tag;
myPanels[index].Focus(); //panel.Focus();
myPanels[index].PreviewKeyDown += new PreviewKeyDownEventHandler(panel_KeyDown);
}
private void panel_KeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Up)
{
myPanels[index].Centre = new Point(myPanels[index].Centre.X, myPanels[index].Centre.Y - 10);
MessageBox.Show("" + myPanels[index].Centre.Y);
Invalidate();
}
if (e.KeyCode == Keys.Down)
{
myPanels[index].Centre = new Point(myPanels[index].Centre.X, myPanels[index].Centre.Y + 10);
MessageBox.Show("" + myPanels[index].Centre.Y);
Invalidate();
}
}
private void test()
{
//for (int i = 0; i < 4; i++)
int i=0;
foreach(var value in arrayPoints_milestones)
{
CircleButton panel = new CircleButton();
panel.Tag = i;
panel.Centre = new Point(arrayPoints_milestones[i].X + i * 10, arrayPoints_milestones[i].Y);
panel.Radius = 10;
panel.BackColor = Color.Red;
panel.Message = "Index: " + panel.Tag.ToString();
myPanels.Add(panel); // qui aggiungo il pannello alla lista di pannelli myPanels
pictureBox1.Controls.Add(myPanels[i]);
myPanels[i].Click += new EventHandler(panel_Click);
i++;
}
}
}
and this is the custom panel class:
public class CircleButton : Panel
{
//Properties to draw circle
float radius;
public float Radius
{
get { return radius; }
set
{
radius = value;
this.Size = new Size((int)Radius, (int)Radius);
}
}
public string Name
{
get;
set;
}
Point centre;
public Point Centre
{
get { return centre; }
set
{
centre = value;
this.Location = Centre;
}
}
public string Message { get; set; }
public CircleButton()
{
//Default Values
Name = "panel_base";
this.BackColor = Color.Black;
Radius = 1;
Centre = new Point(0, 0);
this.DoubleBuffered = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
//Defines a graphic path and set it as the panel's region
//For custom region use different path's
if (centre != null)
{
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, radius, radius);
this.Region = new Region(path);
path.Dispose();
}
}
}
Each time you click a panel, a PreviewKeyDownEventHandler is added - so 3 clicks will trigger 3 (different) eventhandlers with the same invocation target, and each will move your panel for 10 pixels up/down:
protected void panel_Click(object sender, EventArgs e) {
CircleButton panel = sender as CircleButton;
index = (int)panel.Tag;
myPanels[index].Focus(); //panel.Focus();
myPanels[index].PreviewKeyDown += new PreviewKeyDownEventHandler(panel_KeyDown);
}
Updated code for FormView:
public partial class FormView : Form {
List<CircleButton> myPanels = new List<CircleButton>(); // local use only in my example
Point[] arrayPoints_milestones; //not needed anymore
int index; //not needed anymore
public FormView() {
InitializeComponent();
this.Load += FormView_Load;
}
void FormView_Load(object sender, EventArgs args) {
Point panelOffset = new Point(20, 20);
for (int i = 0; i < 4; i++) {
var panel = new CircleButton() {
Name = "panel" + i, //Attention! You have hidden the property "Name" in "Control" with a re-declaration in "CircleButton"
Tag = i, //not needed anymore, right?
Centre = new Point(panelOffset.X + i * 10, panelOffset.Y),
Radius = 10,
BackColor = Color.Red,
Message = "Index: " + i.ToString(),
};
panel.Click += (s, e) => {
panel.Focus();
};
panel.PreviewKeyDown += (s, e) => {
if(e.KeyCode == Keys.Up) {
Point centre = panel.Centre; //copy value
centre.Y -= 10;
panel.Centre = centre; //assign modified copy
Invalidate();
}
if(e.KeyCode == Keys.Down) {
Point centre = panel.Centre; //copy value
centre.Y += 10;
panel.Centre = centre; //assign modified copy
Invalidate();
}
};
myPanels.Add(panel);
pictureBox1.Controls.Add(panel);
}
}
}

Categories

Resources