Returning a function in C# - c#

I have this snippet
private void westButton_click(object sender, EventArgs ea)
{
PlayerCharacter.Go(Direction.West);
}
repeated for North, South and East.
How can I declare a function that'd let me generate methods like ir programmatically?
e.g., I'd like to be able to call
northButton.Click += GoMethod(Direction.North);
instead of defining the method, and then
northButton.Click += new EventHandler(northButton.Click);

northButton.Click += (s, e) => GoMethod(Direction.North);
(or...)
northButton.Click += (s, e) => PlayerCharacter.Go(Direction.North);

I seem to have found a solution:
private EventHandler GoMethod(Direction dir)
{
return new EventHandler((object sender, EventArgs ea) => PlayerCharacter.Go(dir));
}
My only concern would be about binding time; if PlayerCharacter is null when I call GoMethod, what would happen?

northButton.Click += (s,e) => GoMethod(Direction.North);

Related

C# WinForm multiple click event handlers for similar function

I have a few toolStripMenuItems that act as a useful links for a series of websites, a rough example of the code would be something like:
private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
Process.Start("http://www.google.com");
}
private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
Process.Start("http://www.bing.com");
}
private void toolStripMenuItem3_Click(object sender, EventArgs e)
{
Process.Start("https://www.duckduckgo.com");
}
private void toolStripMenuItem4_Click(object sender, EventArgs e)
{
Process.Start("http://www.yahoo.com/");
}
...
Is there a more elegant way to handle this?
Put urls in menu items tag and attach this handler to all of them (hope it works)
private void toolStripMenuItemClick(object sender, EventArgs e)
{
Process.Start(sender.Tag.ToString());
}
The first thing to do is use the same handler for each one:
toolStripMenu1.Click += toolStripItemClick;
toolStripMenu2.Click += toolStripItemClick;
// etc
I would use the Tag property for this, set it when you're constructing the toolStripItems:
toolStripMenu1.Tag = "http://www.google.com";
And then define your handler:
private void toolStripItemClick(object sender, EventArgs e)
{
var c = (ToolStripMenuItem)sender;
Process.Start(c.Tag.ToString());
}
"Mash" all of the event handlers into one and then use the sender to see what ToolStripMenuItem was clicked.
private void toolStripMenuItem_Click(object sender, EventArgs e)
{
if(sender == toolStripMenuItem1)
Process.Start("http://www.google.com");
else if(sender == toolStripMenuItem2)
Process.Start("http://www.bing.com");
else if(sender == toolStripMenuItem3)
Process.Start("http://www.duckduckgo.com");
else if(sender == toolStripMenuItem4)
Process.Start("http://www.yahoo.com");
}
Or as Artem notes use the Tag member of the Control to store the String representing which site to visit. Then cast the sender.Tag to a String and use it.
toolStripMenuItem1.Tag = "http://www.google.com";
toolStripMenuItem2.Tag = "http://www.bing.com";
toolStripMenuItem3.Tag = "http://www.duckduckgo.com";
toolStripMenuItem4.Tag = "http://www.yahoo.com";
...
private void toolStripMenuItem_Click(object sender, EventArgs e)
{
Process.Start(sender.Tag.ToString());
}
You can also subscribe to click event using a lambda expression:
toolStripMenuItem1.Click += (_, __) => Process.Start("process1");
toolStripMenuItem2.Click += (_, __) => Process.Start("process2");

C# Remove Event Handler after is called or call it just once

_cefGlueBrowser.LoadEnd += (s, e) =>
{
BeginInvoke(new Action(() =>
{
MyCefStringVisitor visitor = new MyCefStringVisitor(this, m_url);
e.Browser.GetMainFrame().GetSource(visitor);
loaded = true;
}));
};
But problem is that Event Handler is called many times. After each JS reload for example. How to remove multiple calls. How to call LoadEnd event just once.
I try with
_cefGlueBrowser.LoadEnd -= delegate { };
but not working.
What can i do? I want to call it just once!
EventHandler handler = null;
obj.SomeEvent += handler = (s, e) => {
obj.SomeEvent -= handler;
// more stuff
};
This works because it is the variable that us captured (lexical closure), not the value of the variable at any particular time.
Create a method
public void Browser_LoadEnd(object sender, EventArgs e)
{
BeginInvoke(new Action(() =>
{
MyCefStringVisitor visitor = new MyCefStringVisitor(this, m_url);
_cefGlueBrowser.Browser.GetMainFrame().GetSource(visitor);
loaded = true;
}));
}
subscribe
_cefGlueBrowser.LoadEnd += Browser_LoadEnd;
and unsubscribe
_cefGlueBrowser.LoadEnd -= Browser_LoadEnd;
Note, I assume that the LoadEnd event takes EventArgs and not some derived class.
Define the event handler in a separate method and add the unsubscribing operation to its method body:
public EventHandler OnLoadEnd(object sender, <args>)
{
BeginInvoke(new Action(() =>
{
MyCefStringVisitor visitor = new MyCefStringVisitor(this, m_url);
_cefGlueBrowser.Browser.GetMainFrame().GetSource(visitor);
loaded = true;
}));
_cefGlueBrowser.LoadEnd -= OnLoadEnd;
}
Based on Mark Gravel response, I think you need also at least a flag
bool done = false;
EventHandler eh = null;
obj.evt += eh = (_, e) => {
obj.evt -= eh;
if (done)
return;
done = true;
// stuff
};

One function for two events

I have this code that I attach to the DoubleClick event on the Tray Icon for my app:
ni.DoubleClick +=
delegate(object sender, EventArgs args)
{
this.MainWindow.Show();
};
But, is it possible to use this code for two events (DoubleClick and Click), like so:
ni.DoubleClick, ni.Click +=
delegate(object sender, EventArgs args)
{
this.MainWindow.Show();
};
Just for minimalize a code size and readability. Thanks
Put the handler in its own function:
private void ClickHandler(object sender, EventArgs args)
{
this.MainWindow.Show();
}
Then wire it up to both events:
ni.DoubleClick += ClickHandler;
ni.Click += ClickHandler;
Just create EventHandler using lambda expression and add it to both event.
EventHandler e = (sender, args) => this.MainWindow.Show();
ni.DoubleClick += e;
ni.Click += e;
No, but you can make it a standard, non anonymous function and use it for both events.
private void OnClick(object sender, EventArgs e) { ... }
ni.DoubleClick += OnClick;
ni.Click += OnClick;
Just assign it to a variable beforehand:
EventHandler eventHandler = delegate(object sender, EventArgs args)
{
this.MainWindow.Show();
};
ni.DoubleClick += eventHandler;
ni.Click += eventHandler;
BTW, the event handler definition can be simplified using the anonymous method syntax:
EventHandler eventHandler = (s, e) => this.MainWindow.Show();

How to Use Dynamically Created Button/textBox in C# Windows Forms?

private void createButton()
{
flowLayoutPanel1.Controls.Clear();
for (int i = 0; i < 4; i++)
{
Button b = new Button();
b.Name = i.ToString();
b.Text = "Button" + i.ToString();
flowLayoutPanel1.Controls.Add(b);
}
}
private void button1_Click(object sender, EventArgs e)
{
createButton();
}
I Used this code to create some buttons on runtime , now how can i use those created buttons to perform diffrent actions? Im kindz new to this so please help me , very much appreciated :)
You can assign an event handler to the click event:
b.Click += SomeMethod;
SomeMethod must have the following signature:
void SomeMethod(object sender, EventArgs e)
b.Click += delegate(object sender, EventArgs e) {
Button clickedButton = (Button)sender; //gets the clicked button
});
When you create your button, you need to subscribe to the Click event like this :
Button b = new Button();
b.Click += new EventHandler(b_Click);
// or
b.Click += b_Click;
// or
b.Click += delegate(object sender, EventArgs e) {/* any action */});
// or
b.Click += (s, e) => { /* any action */ };
void b_Click(object sender, EventArgs e)
{
// any action
}
This is something that is automatically done when your are is the designer in Visual Studio, and you click on a button to create the method button1_Click.
You can search in the Designer.cs of your form, you will find an equivalent line:
button1.Click += new EventHandler(button1_Click);
Related question:
How can i create dynamic button click event on dynamic button

Adding delegate functions first single use

I have a button which slides out a menu using a storyboard by calling begin() on it like so
private void ShareBtn_Click(object sender, RoutedEventArgs e)
{
SlideIn.Begin();
}
On the grid which then slides out there are buttons.
Each button then slides the grid back and when that storyboard completes the action for the button then runs so like so,
private void PictureBtn_Click(object sender, RoutedEventArgs e)
{
CertificateDisplay.SaveAsPicture();
}
private void FacebookBtn_Click(object sender, RoutedEventArgs e)
{
App.facebookSuccess = false;
NavigationService.Navigate(new Uri("/FBLogin.xaml", UriKind.Relative));
}
private void SMSBtn_Click(object sender, RoutedEventArgs e)
{
SlideOut.Begin();
SlideOut.Completed += delegate(object s, EventArgs se) { SlideOut_Completed(s, se, "Email"); };
}
private void EmailBtn_Click(object sender, RoutedEventArgs e)
{
SlideOut.Begin();
SlideOut.Completed += delegate(object s, EventArgs se) { SlideOut_Completed(s, se, "Email"); };
}
void SlideOut_Completed(object sender, EventArgs e, String shareType)
{
switch (shareType)
{
case "Email":
...
default:
break;
}
}
The flaw I encountered if that I cannot remove the anonymous functions from the event stack.
I've managed to solve it by making shareType a common variable for all of the above functions and not using a anonymous delegate and then removing the "named" functions from the event stack when OnNavigatedFrom is called.
Is there a way to do this by still using those delegates because it looks neater?
One option is to remove it within the handler itself:
EventHandler handler = null;
handler = delegate(object s, EventArgs se) {
SlideOut_Completed(s, se, "Email");
SlideOut.Completed -= handler;
};
SlideOut.Completed += handler;
SlideOut.Begin();
Why assign the Completed event handler EmailBtn_Click at each click? Do it in the form constructor or in the form load event.

Categories