Background
I have created linklabels in a loop dynamically which are created using a function, gets it's name from database tables. (which is stated as users_decks in the code)
I've checked other questions, and they mostly wrote a function like the one i'll state at the end, but those didn't just work.
But I've been struggling how to set an event listener for those linklabes, like clicking twice on them in the designer?
Code
private void create_Dynamic_label_Texts()
{
try
{
int x = 130;
int y = 35;
foreach (var deck in Deck_Owner.users_decks)
{
LinkLabel deck_1 = new LinkLabel();
deck_1.Text = " " deck;
deck_1.LinkBehavior = LinkBehavior.NeverUnderline;
deck_1.LinkVisited = false;
deck_1.AutoSize = false;
deck_1.BackColor = Color.LightGray;
deck_1.LinkColor = Color.Black;
deck_1.Location = new Point(x, y);
deck_1.Size = new Size(270, 20);
Controls.Add(deck_1);
deck_1.Show();
y = y 24;
}
}
catch
{
lblNoDeck.Text = "You haven't created decks yet! Create some to start.";
}
}
What I would like to happen?
When Link Labels are created, I want them to open a user control, I've tried writing a function.
For example
private void deck_1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
MessageBox.Show("sadadsdasdas");
panel1.Controls.Add(myUserControl);
}
This just...doesn't work, and I couldn't get to figure out why, messagebox doesn't come up either, when the linklabel is clicked.
CodePudding user response:
The part you're missing, in your understanding, is what happens when you double click on a link in the designer. There is no magic; there is only code you don't normally see
Here's a new Form, with a LinkLabel:
Here's what you get when you double click it:
But, hopefully, here's the lightbulb moment:
Every form has a partial class where the windows forms designer writes all its code. You write your code into Form2.cs; it writes into Form2.Designer.cs. This way all the verbosity it writes is tucked away out of sight (and it should only ever be modified manually with care, or a backup.. Another good reason to keep it out of the way!)
Because it's a partial
class, C# merges them into one when compiling. This is how all the code the designer writes gets merged with yours to do useful things
The form designer writes this:
this.linkLabel1.LinkClicked =
new System.Windows.Forms.LinkLabelLinkClickedEventHandler(
this.linkLabel1_LinkClicked
^^^^^^^^^^^^^^^^^^^^^^^^^^^
this method is in Form2.cs
);
..and the linkLabel1_LinkClicked
is the method in "your" code; there's the glue of how clicking on one of the designer's linklabels calls code that you wrote
--
Now, you're effectively doing (in your code in the question) what the designer normally does in its code; you're building a UI, positioning and sizing components etc and you're doing it programmatically. You need to wire your events up programmatically too
You can do exactly the same as the designer has done when it wired up the LinkCLicked event. Under your line:
deck_1.Size = new Size(270, 20);
You can put:
deck_1.LinkClicked = new LinkLabelLinkClickedEventHandler(deck_1_LinkClicked);
You can even shorten it a bit:
deck_1.LinkClicked = deck_1_LinkClicked;
This will connect all of your linklabels to the same handler; you can use the sender
argument to work out which one was clicked.
Optionally you could give each one a different handler:
deck_1.LinkClicked = (s, e) => {
MessageBox.Show("linkLabel at Y coordinate " deck_1.Location.Y " was clicked");
panel1.Controls.Add(myUserControl);
}
This would mean that each linklabel had a different method handling the click event; (s,e) => { MessageBox.Show(...) }
is a sort of miniature, nameless, method (a lambda) - it embodies the functionality you want to carry out. It's hard to advise more on what you'd want the method body of it to do because your posted example handler doesn't do anything dynamic/varying.
I put the Y into the messagebox call to demontrate how the variables you use in the loop will be captured and remembered so the code still works in 5 minutes time when it's called..
..but on that note beware - if you reference e.g. y
inside the body of this handler, it won't be the value of y
at the time the handler was created, it will be the value of it at the time it was executed - subtle difference that leads to obscure bugs.
//beware! this messagebox shows 275 for every linklabel, if there are 10 labels, because 275 is the resting value of a loop that does 35 (10 * 24)
deck_1.LinkClicked = (s, e) => {
MessageBox.Show("linkLabel at Y coordinate " y " was clicked");
panel1.Controls.Add(myUserControl);
}
Simple rule of thumb is "don't use, in a lambda like this, variables that have their values modified - only ever refer to variables you don't modify, or variables that are modified by making a new
object for them"