How to extend MouseEventHandler function - c#

first, I would like to apologize for my lack of knowledge, but I am new in C# and I am missing some basic principles.
Here is my current scenario:
In my scenario I create something like chess desk of pictureboxes. They are placed inside of control "Panel" in Winform form - panel is scrollable!
Each picture box has unique name like pbR1_C1 generated in constructor.
R - stands for Row on desk
C - Stands for Column on desk
All is made during runtime since the chess desk size is loaded after program starts. Used objects look like this:
/* Simple preview of object with public variables - just for preview */
public class ptFcElement
{
public string stName; /* "pbR1_C1", "pbR1_C2" */
public int iRow; /* 1 */
public int iColumn; /* 4 */
public PictureBox pbPictureBox; /* using System.Drawing;*/
public ptFcElement()
{
stName = sGenerateName();
}
}
Then I assign event handler for each picture box
ptFcElementTemp.pbPictureBox.MouseClick += new MouseEventHandler(MouseButton_Click);
At this point I am able to identify that I have pressed some picture box, but I don't know which one.
Here is the question:
Since panel is scrollable - I can not simple identify pressed picture box - it always calls the same function.
void MouseButton_Click(object sender, MouseEventArgs e)
{
//Do some stuff....
//In case panel is not scrollable,
//I can identify pressed picture box by coordinates of mouse click.
//But if panel is scrollable, I am screwed.
}
Desired idea:
Is there any possibility to extend MouseEventHandler event function? I know that simple classes are easily to extend, but I am not sure how to work with event functions.
ptFcElementTemp.pbPictureBox.MouseClick +=
new MouseEventHandler(MouseButton_Click, "pbR1_C1");
void MouseButton_Click(object sender, MouseEventArgs e, string sUniqueName)
{
//Here I am able to identify pressed bisturebox by sUniqueName
if (sUniqueName == "pbR1_C1")
{
//do something
}
if (sUniqueName == "pbR2_C3")
{
//do something different
}
}
Thank you, see you.
And please, explain it as easy as possible, for dummy. :-)

You could try it like this:
void MouseButton_Click(object sender, MouseEventArgs e)
{
var pb = sender as PictureBox;
if(pb!=null){
//Do something with the instance the PictureBox which fired the event
}
}
After discussion with Yacoub Massad I want to suggest you following enhancement:
Declare your own event, which you fire when the PictureBox is clicked.
public class ptFcElement {
public string stName; /* "pbR1_C1", "pbR1_C2" */
public int iRow; /* 1 */
public int iColumn; /* 4 */
public PictureBox pbPictureBox; /* using System.Drawing;*/
public event EventHandler PictureBoxWasClicked;
protected virtual void OnPictureBoxWasClicked(){
if (this.PictureBoxWasClicked != null)
this.PictureBoxWasClicked(this, new EventArgs());
}
public ptFcElement() {
stName = sGenerateName();
this.pbPictureBox.Click += pbPictureBox_Click;
}
private void pbPictureBox_Click(object sender, EventArgs e) {
this.OnPictureBoxWasClicked();
}
}
Outside you can react on this event instead of the PictureBox' Click-event. The "sender" will be the instance of your own class directly.
If you want you could even define an own EventArgs-class to pass what ever parameters you like...

As a direct answer to your question, you can do something like this:
ptFcElementTemp.pbPictureBox.MouseClick +=
(object sndr, MouseEventArgs m_args)
=> MouseButton_Click(sndr, m_args, "pbR1_C1");
You can pass whatever parameter that you want.
This is helpful if you want more context than just the PictureBox that was clicked since that object can be access using the sender parameter. For example, you might want to get access to the corresponding ptFcElement.

Basically you are trying to determine wich control was clicked? I hope that's what you're asking for.
The sender parameter contains your control.
For example:
if (sender==ptFcElementTemp.pbPictureBox){
//Do stuff
}
else if(sender==ptFcElementTemp.otherControl){
//Do other stuff
}

Related

C# Execute Method for selected CheckBoxes. Different Method for each CheckBox

So I have a bunch of CheckBoxes on a Form with a Button at the bottom that I want to click and it Executes the Methods for those Checked CheckBoxes.
Each CheckBox will use its own Method.
Seems Like a Common/Simple thing to do. Yet I have found nothing too helpful searching around regarding dealing with multiple CheckBoxes on one Event.
I am relatively new to programming and I'm learning on my own.
Idk if there's a simple for or foreach loop I can use in conjunction with something else to make this simpler, but I don't even know a long way to make it work...
All I can Come up with is a bunch of if statements under button click event to test if checked and if so run method. However, this seems like the wrong way to do this.
private void btnExecutedSelected_Click(object sender, EventArgs e)
{
if (ChkBox_Test.Checked == true)
{
ClassName.MethodName();
}
//Then an if statement for each CheckBox
}
Any Help Much Appreciated
There are several ways to approach this, and usually the best ways are a little more advanced, but this is a good opportunity to learn some basics about delegates, which are like a mix between variables and methods/functions. For now, think of them like a card in Monopoly that tells you to go directly to jail. The card itself isn't really anything except an instruction that you pick up. When you USE / read the card, you have to follow the resulting instruction, which is to go to jail. So delegates are sort of like those cards.
To get an idea of how they work, create a new Winforms app, drop 4 checkboxes on the form and a button. Don't worry about renaming them. Then add in the following code:
// This defines the "monopoly cards"
// Community Chest cards give or take money, so we'll expect an int to be returned
public delegate int CommunityChestCard();
// Chance cards just do things without any return values
public delegate void ChanceCard();
private void Form1_Load(object sender, EventArgs e)
{
checkBox1.Tag = new ChanceCard(GoDirectlyToJail);
checkBox2.Tag = new ChanceCard(AdvanceToGo);
checkBox3.Tag = new CommunityChestCard(WinBeautyContest);
checkBox4.Tag = new CommunityChestCard(PayDoctorsFees);
}
private void GoDirectlyToJail()
{
MessageBox.Show("You went to jail!");
}
private void AdvanceToGo()
{
MessageBox.Show("You advanced to Go!");
}
private int WinBeautyContest()
{
MessageBox.Show("You won $20 in a beauty contest!");
return 20;
}
private int PayDoctorsFees()
{
MessageBox.Show("You had to pay $50 in doctor's fees!");
return -50;
}
// Now when we click the button, we'll loop through our checkboxes,
// see which ones were checked, and then execute the methods defined
// in the associated chance/communitychest cards.
private void button1_Click(object sender, EventArgs e)
{
// this.Controls is a collection of the child controls on the current form
foreach(Control ctl in this.Controls)
{
// See if the control is a CheckBox
if(ctl is CheckBox)
{
// It is - let's cast it for easier coding...
CheckBox chk = (CheckBox)ctl;
// Is it checked?
if (chk.Checked)
{
// Yep! Does it have a value in its Tag?
if (chk.Tag != null)
{
if(chk.Tag is CommunityChestCard)
{
CommunityChestCard ccCard = (CommunityChestCard)chk.Tag;
// Call the function on the card and get the result
int adjustMoneyByAmount = ccCard();
}
else if(chk.Tag is ChanceCard)
{
ChanceCard cCard = (ChanceCard)chk.Tag;
// Call the function on the card
cCard();
}
}
}
}
}
}
Now, just some words of warning - I used the Tag property as a quick fix to cut down on extra coding for illustration purposes. As you get better with code and custom/extended controls, you might want to have your own properly-typed properties for these kinds of things. Using Tag is NOT an elegant solution.
If you run that code as described, you should be able to check some of the checkboxes and click the button and see the resulting functions being executed.
I'd also suggest not just looping through all the controls on a form and checking to see if they're checkboxes. You seemed to have some trouble with looping through controls, so that approach was there as an example. Checkboxes can be grouped together in many different ways. You might consider a List object and adding your checkboxes to that list. That way, you can simply loop through that List later and you'll know exactly which controls you're dealing with (no ugly casting or checking to see if a control is a checkbox).
You can do something like this:
private void CheckBoxOperations(Control parentControl)
{
foreach (Control c in parentControl.Controls)
{
if (c is CheckBox)
{
if (((CheckBox)c).Checked)
{
//DoSomething
}
}
if (c.HasChildren)
{
CheckBoxOperations(c);
}
}
}
private void btnExecutedSelected_Click(object sender, EventArgs e)
{
CheckBoxOperations(this);
}

How to Hide and Show a button with if statements c#

I am trying to make a button visible = false if a quantity in a text box is less than or equal to 0. The problem I am having is that you have to click the button in order to activate the function.
Here is my code so far
int quantity = int.Parse(textBox33.Text);
if (quantity <= 0)
button13.Visible = false;
if (quantity > 0)
button13.Visible = true;
do I have to disable the visibility of the text box beforehand?
Simply go to the form editor and double click on the textbox. In the code presented to you after double clicking add your code or double click on the form itself if you want the code to be executed whenever the form is loaded.
At first you should encapsulate the code to update the button in a specific method:
private void UpdateButton13()
{
button13.Visible = quantity > 0; // no need for if/else
}
Then you can call this from every event after which the button should be updated. From your comments it seems you want to update that button
at Form load and
when the text in textBox33 has been changed.
So for example:
public class YourForm : Form
{
public YourForm()
{
InitializeComponents();
// register event handlers:
Load += YourForm_Load;
textBox33.TextChanged += textBox33_TextChanged;
}
private void YourForm_Load(object sender, EventArgs e)
{
UpdateButton13();
}
private void textBox33_TextChanged(object sender, EventArgs e)
{
UpdateButton13();
}
private void UpdateButton13()
{
button13.Visible = quantity > 0; // no need for if/else
}
}
Of course you can also create and register the event handlers in the designer window, without having to write the code in the constructor yourself.
The code above may now seem a little redundant (same code in two methods and a one-line method). But I assume that you want to do further things on loading the form and on changing text, and maybe you want to call UpdateButton13 from other parts of your code, too. So encapsulating here is good style (imho) to avoid problems for further development.
go to textbox events and insert the code to textChanged event.
but for better than that you can do digit validation event
private void textBox33_KeyPress(object sender, KeyPressEventArgs e)
{
if (!System.Text.RegularExpressions.Regex.IsMatch(e.KeyChar.ToString(), "[1-9]"))
{
e.Handled = true;
}
}
in that case order can be only positive number

Buttons in a Visual Studios form application

Sorry if this is a dumb question, I'm taking an intro to programming class and need a bit of help with this project I'm working on.
I'm trying to write an application that has about 30 buttons. One common thing I want is for all the buttons to turn yellow when clicked. If they're clicked a second time, they change back to the default color. right now I use the code:
private void btn_1_Click(object sender, EventArgs e)
{
btn_1.BackColor = Color.Yellow;
}
But that only turns the buttons yellow, I can't turn them "off" by clicking it a second time.
Also, when I'm creating these button events in VS2010, I end up with 30 different event handlers for each button..Is there a way to get them all to do the same thing without having to write all the repetitive code?
I'm guessing that I would have to write my own buttons class? How would I go about doing that? Do i need to create a class library which inherits Buttons?
Sorry for the noob questions. THanks
If every button has a specific action that needs to be performed, then yes, you need to have a click handler for each; however, you can encapsulate the common behavior in a single method.
For example:
private void btn_1_Click(object sender, EventArgs e)
{
ToggleColor((Button)sender);
//rest of the code specific to this button
}
private void ToggleColor (Button button)
{
if(button.Color==Color.Yellow;
button.Color=Color.Black;
else
button.Color=Color.Yellow;
}
Note that above code is not tested.
Now, if all the buttons do the same thing, you can just set the on click handlers for all of them to be btn_1_Click; for example.
private void btn_1_Click(object sender, EventArgs e)
{
if (btn_1.BackColor != Color.Yellow)
{
btn_1.BackColor = Color.Yellow
}
else
{
btn_1.BackColor = Color.Control;
}
}
this is switching default and yellow
If all buttons do the exact same thing you can assign the same event handler to all buttons (instead of btn_1_Click, btn_2_Click etc... you'd have btton_click) - you can select this handler in the properties of each button.
You don't have to write your own class. You can simply assign all your buttons to the same event handler, like this:
button1.Click += new EventHandler(myEventHandler);
button2.Click += new EventHandler(myEventHandler);
button3.Click += new EventHandler(myEventHandler);
button4.Click += new EventHandler(myEventHandler);
Just keep in mind that your event handler has this signature:
private void myEventHandler(object sender, EventArgs e)
By doing that, all your buttons, when clicked, will trigger the same method.
Now to control the color, what you can do is create a simple property on your form which would hold the last color applied. It could be an enum, then you could simply check its value and apply the other one to the buttons, like this:
// Declare your enum:
private enum Colors { Yellow, Default }
private Colors ActualColor = Colors.Default;
// Write your custom event handler:
private void myEventHandler(object sender, EventArgs e)
{
if (ActualColor == Colors.Default)
{
// Apply yellow to buttons
ActualColor = Colors.Yellow;
}
else
{
// Apply default
ActualColor = Colors.Default;
}
}
In order to keep track whether it is the 'second time' you press the button, you should declare a variable OUTSIDE the method, which indicates whether you already pressed the button or not.
For example:
public bool IsButtonYellow;
private void btn_1_Click(object sender, EventArgs e) {
if(!IsButtonYellow) {
btn.BackColor = Color.Yellow;
IsButtonYellow = true;
}
else {
btn.BackColor = Control.DefaultBackColor;
IsButtonYellow = false;
}
}
Yes:
Create your own button class
Inherit from Button
Implement the handler in your button class and you're done
You can do something simple like this:
public class MyButton : Button
{
private bool _buttonState;
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
if (_buttonState)
{
BackColor = Color.Yellow;
}
else
{
BackColor = Color.White;
}
}
}
Then in your code you can just create as many of these "MyButton" objects as you need, with no code repetition.
To make all buttons use the same event handler in VS2010:
Click once on a button to select it.
In the “properties” window: click on the “lightning” (=events).
Paste the first button’s event name (btn_1_Click) next to “Click”.
Do the same for every button.
As for changing the color:
See answer by killie01.
Good luck.

How do I create a custom C# control that has some common functionality?

I am very new to C# programming. I come from autoit, and other scripting languages, the transition has been most difficult. Anyway I am working on a control in a windows form, basically I want it to be a LinkLabel control, that when you click it, it will become a textbox, once you enter your name, and either hit enter, or tab, it will set your name as the linklabel. But, I will have 10 of these controls on a form, and the way I have done it, it has taken three methods per control, so that is a lot of code, I'm sure I'm just doing it wrong, but here is what i have:
namespace Program
{
public partial class formMain : Form
{
public formMain()
{
InitializeComponent();
}
private void linkLabelPlayerName1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
this.linkLabelPlayerName1.Hide();
this.textBoxPlayerName1.Show();
this.textBoxPlayerName1.Focus();
this.textBoxPlayerName1.KeyPress += new KeyPressEventHandler(textBoxPlayerName1_KeyPress);
this.textBoxPlayerName1.LostFocus += new EventHandler(textBoxPlayerName1_LostFocus);
}
private void textBoxPlayerName1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
this.linkLabelPlayerName1.Text = this.textBoxPlayerName1.Text;
this.textBoxPlayerName1.Hide();
this.linkLabelPlayerName1.Show();
}
}
private void textBoxPlayerName1_LostFocus(object sender, EventArgs e)
{
this.linkLabelPlayerName1.Text = this.textBoxPlayerName1.Text;
this.textBoxPlayerName1.Hide();
this.linkLabelPlayerName1.Show();
}
}
}
I'm sure there is a way to use the last two methods between all 10 controls, so they don't have to be rewritten for each control. That is, textBoxPlayerName1_LostFocus() and textBoxPlayerName2_LostFocus().
Welcome to object orientated programming :).
You should created a derived class to encapsulate the functionality. For example:
class EditableText : UserControl
{
private LinkLabel lblName;
private TextBox txtName;
public EditableText()
{
// Construct objects, attach events and add them
// as children to this object
}
// Return the text of encapsulated TextBox
public string Text
{
get { return txtName.Text; }
}
}
Now you are able re-use this class in different areas, that's what object orientated programing all about!
Right-click on the windows forms application in the Solution Exporer, and select Add, then User Control...
Type in a name for the new control, like LinkLabelTextBox
This will give you a space to work in that looks like a Form, but without borders. This is your new control. Put your LinkLable and TextBox on this new control exactly as you put them in the window, and give them the functionality that you want. Then replace all your existing controls with instances of this new control. You will create 10 of these, instead of creating ten LinkLabels and ten TextBoxes. And all of the functionality that you want will be built-in to your new control, so that code does not need to be repeated.
Instead of a linkLabelPlayerName1 and textBoxPlayerName1, you will have a linkLabelTextBoxPlayerName1, and none of the Show, Hide, Focus stuff will clutter your form code.
Also, be sure to include a public Text property so you can get the value that the user typed out of this control.
Create your own Control with the functionality.
Your code is correct.
To make it cleaner, you should move it to a separate UserControl, and set the Text property to the textbox's value.

How to display all the tooltips that are already associated to controls

I have a form with controls and associated tooltips. I'm implementing a help-button which should show all the tooltips at once.
I would like to implement it somehow like this:
private void btnHelp_Click(object sender, EventArgs e)
{
System.Windows.Forms.Control.All.Show.Their.Tooltips();
}
Can't find a simple way to do it :-)
I was thinking of using ToolTip.Show() but it requires not only the control, but also the tooltip text - but I don't want to write it again (since necessary tooltips are already assigned in controls' properties).
UPD.
I started implementing it with this function:
public void ShowControlsTooltip(System.Windows.Forms.Control c)
{
ttsToolTips.Show(ttsToolTips.GetToolTip(c), c, c.Location.X, c.Location.Y);
}
But I can't make it show multiple tooltips at the same time.
UPD2.
Now I have this kind of code, but all tooltips still blink and disappear.
public void ShowControlsTooltip(System.Windows.Forms.Control c)
{
ToolTip t = new ToolTip();
//t = ttsToolTips;
t.Show(ttsToolTips.GetToolTip(c), c, c.Location.X, c.Location.Y, 1000);
}
private void btnHelp_Click(object sender, EventArgs e)
{
foreach (Control c in this.Controls)
{
try
{
ShowControlsTooltip(c);
}
catch
{
}
}
}
The thing with ttsToolTips is that I have all the tooltips associations there already.
UPD3. it looks like works. But coordinates are not exact.
The big question is now - how to remove all these tooltips at once?
foreach(Control c in Form.Controls)
{
string s = Tooltip.GetTooltip(c);
c.ShowTooltip(s,this);
}

Categories

Resources