IntelliSense says that the lambda parameter ea is a DownloadStringCompletedEvent Args. Understood, but parameter s is only defined as "object s". Can anyone explain the purpose of this parameter?
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, ea) =>
{ XDocument document = XDocument.Parse(ea.Result);
// ... Do something else...
};
AFAIK that object s is usually known as the "Sender", hence the s for sender - ie. the object that generate the event, aka, the source.
Hope this helps.
EventHandlers in .NET are typically of the form
void MyEventHandler(object sender, EventArgs e) { ... }
The sender argument is the object that the event occurred on. Since it can be just about anything, object is used. The EventArgs argument is typically either System.EventArgs itself, or a subclass of it. In your case it is a subclass.
The lambda matches the delegate
public delegate void DownloadStringCompletedEventHandler(
Object sender,
DownloadStringCompletedEventArgs e
)
Where s is "The source of the event."
http://msdn.microsoft.com/en-us/library/system.net.downloadstringcompletedeventhandler.aspx
Related
I'm using the DoubleUpDown control from WPFToolkit and I'm trying to create an event handler using ValueChanged.
DoubleUpDown dud = new DoubleUpDown();
dud.ValueChanged += new RoutedPropertyChangedEventHandler<double>(DoubleUpDown_ValueChanged);
private void DoubleUpDown_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
}
I get the error message
CS0029 Cannot implicitly convert type
'System.Windows.RoutedPropertyChangedEventHandler double' to
'System.Windows.RoutedPropertyChangedEventHandler object'
Any suggestions on how this can be addressed to ensure no type conflicts? Thanks.
As the erros suggests, ValueChanged is expecting a RoutedPropertyChangedEventHandler<object>, so you would have to do this:
DoubleUpDown dud = new DoubleUpDown();
dud.ValueChanged += new RoutedPropertyChangedEventHandler<object>(DoubleUpDown_ValueChanged);
private void DoubleUpDown_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
}
And inside the handler you will have to cast the object to a double.
Note:
The author left a comment in the source code about that, here:
Due to a bug in Visual Studio, you cannot create event handlers for
generic T args in XAML, so I have to use object instead.
I've just had a delve through the online source code, and it looks like the declaration of that event is...
public event RoutedPropertyChangedEventHandler<object> ValueChanged
So your signature needs to match that by making it...
private void DoubleUpDown_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
Is this what you're intending ?
dud.ValueChanged += DoubleUpDown_ValueChanged;
private void DoubleUpDown_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if(e != null && Math.Abs((double)e.NewValue) < 0.000000001d)
{
// for example
}
}
i hope this may help you
this.dud.ValueChanged += new System.Windows.RoutedPropertyChangedEventHandler<double>(this.dud_ValueChanged);
private void dud_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
I am trying to understand how the lambda operator in C# is used when the given parameters are formatted in ( ), like so:
_backgroundVideoWorker.DoWork += (s, e) =>
{
outputFile = _videoEditor.JoinVideo(selectedConfiguration, videoFiles);
};
My main goal from asking this question is to understand how the different operators are being used with the lambda, += (s, e) =>.
For reference, this code excerpt is taken from an application that is joining two video files together by using the FFMPEG utility.
_backgroundVideoWorker.DoWork is an event that needs handlers.
+= indicates we are adding an event handler to handle the event.
(s, e) is saying that the expression is creating a function which accepts the s and e parameters required by the event for a function to handle it. These represent an object (s) and the DoWorkEventArgs (e). If you were to write a full function block instead of an inline lambda, they would look like (object s, DoWorkEventArgs e) or more familiarly (object sender, DoWorkEventArgs e);
BackgroudWorker.DoWork is an event with a delegate type of DoWorkEventHandler, which has the signature:
public delegate void DoWorkEventHandler(object sender, DoWorkEventArgs e)
which means that DoWork would be a function that receives two parameters, of type object and DoWorkEventArgs, respectively.
The event handler has to follow the same signature as the event's delegate, therefore, when you speficy (s, e) => { /*..*/ } as the event handler, the compiler will assume that s corresponds to the object sender parameter, while e corresponds to the DoWorkEventargs e parameter. Of course, you don't have to name them s and e
I want to pass an argument to an event handler which I am trying to achieve with this code:
private void openInputImagesToolStripMenuItem_Click(object sender, EventArgs e)
{
...
pb.MouseDoubleClick += new MouseEventHandler((sender,e) => showLargeImage(sender,e,imageIndex));
}
private void showLargeImage(object sender, MouseEventArgs e, int imageIndex)
{
...
}
However, I am getting an error on "sender" and "e" variables inside the adapter:
A local variable named 'sender' cannot be declared in this scope because it would give a different meaning to 'sender', which is already used in a 'parent or current' scope to denote something else.
A local variable named 'e' cannot be declared in this scope because it would give a different meaning to 'sender', which is already used in a 'parent or current' scope to denote something else.
How can I solve this?
You can't name the parameter of your lambda method sender and e, as the compiler tells you.
It would create a ambiguity between the parameter sender of the openInputImagesToolStripMenuItem_Click method and the parameter of the lambda method.
Just use other names, like
pb.MouseDoubleClick += new MouseEventHandler((s, e1) => showLargeImage(s, e1,imageIndex));
Should be enough to change sender to something else, say se:
pb.MouseDoubleClick +=
new MouseEventHandler((se,e) => showLargeImage(se,e,imageIndex));
You have redefinition of sender and e inside your lambda and that is no allowed:
private void openInputImagesToolStripMenuItem_Click(object sender, EventArgs e)
{
...
pb.MouseDoubleClick += new MouseEventHandler((s,x) => showLargeImage(sender,e,imageIndex));
}
I'm trying to implement drag and drop for a specific object of a Type that I've created in c# for windows phone 8. I'm using Manipulation Events like this :
deck[r[i, j]].card.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(ImageManipulationCompleted);
private void ImageManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
//something
}
How can I change object to the type that I want ?
keyboardP's solution will work just fine. But I personally prefer to store the information I need in the Tag property of the control, which has been designed for this very purpose.
deck[r[i, j]].card.Tag = deck[r[i, j]];
deck[r[i, j]].card.ManipulationCompleted += ImageManipulationCompleted;
private void ImageManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
var deck = (Deck)((FrameworkElement)sender).Tag;
}
The good side of keyboardP's approach is that, since you receive directly the desired object as a parameter of your method, it's easier to read. The downside is that you have to declare a custom delegate for every event you need, and you lose the ability to assign event handlers directly from the XAML. My solution is a bit harder to read, but addresses this point.
In the end, which solution is better really depends on your tastes and your needs.
What you could do is just call a method that takes in your type instead of using the standard ImageManipulationCompleted handler. I don't know what the deck[r[i, j]] type is but you can replace MyType below with the correct type.
deck[r[i, j]].card.ManipulationCompleted += delegate(object s, ManipulationCompletedEventArgs e){ CardManipulated(s, e, deck[r[i, j]]); };
private void CardManipulated(object sender, ManipulationCompletedEventArgs e, MyType selectedObject)
{
//you know have access to selectedObject which is of type deck[r[i, j]],
//the ManipluationCompletedEvents properties if needed,
//and the actual card Image object (sender).
}
You cant.
Since you are subscribing to an event with this code new EventHandler<>(..), you cannot change the type of sender because in the description of EventHandler<> there is only object sender:
public delegate EventHandler<T>(object sender, T eventArgs) where T : EventArgs
If you need to create your own delegate, you could make a factory or simply write this:
public delegate EventHandler<T, TArgs>(T sender, TArgs eventArgs) where TTArgs : EventArgs
ManipulationCompletedEventHandler signature is using object in its first parameter
public delegate void ManipulationCompletedEventHandler(object sender,
ManipulationCompletedRoutedEventArgs e);
So, you can't change the signature but you can use delegate to typecast object always to your type like this -
deck[r[i, j]].card.ManipulationCompleted += (s, e) =>
ManipulateMe_ManipulationCompleted((YourType)s, e);
private void ImageManipulationCompleted(YourType sender,
ManipulationCompletedEventArgs e)
{
//something
}
Replace YourType with your desired Type (TextBox or something whichever you want)
private void dateTimePicker1_ValueChanged(object sender, Series myseries, int multiplier, EventArgs e)
{
if (datelimitsset == 1) {
var dt1 = dateTimePicker1.Value;
chart1.Series.Clear();
for (int i = 0; i < multiplier; i++)
{
config();
myseries.Points.AddXY(Convert.ToString(date[i]), Convert.ToDouble(array[i]));
string[] rowi = { Convert.ToString(date[i]), Convert.ToString(array[i]) };
dataGridView1.Rows.Add(rowi);
}
}
}
This is giving me the error:
No overload for 'dateTimePicker1_ValueChanged' matches delegate 'System.EventHandler'
I do not fully understand event handlers, can anyone give me advice?
The signature for System.EventHandler is (object sender, EventArgs e) so you either need to change your method signature to this:
private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
Or keep your current signature and use a lambda expression as a delegate adapter when you subscribe to the event:
dateTimePicker1.ValueChanged += (object sender, EventArgs e) =>
dateTimePicker1_ValueChanged(sender, [your Series variable], [your int multiplier variable], e);
When you use a lambda expression as a delegate adapter, you are essentially creating a delegate which conforms to the System.EventHandler signature (it is passed an object and an EventArgs argument), which then calls your original handler method passing all of the arguments required to satisfy your dateTimePicker1_ValueChanged method.
The reference documentation for the System.EventHandler delegate.
EDIT: documentation for an example handler for the DateTimePicker.ValueChanged event
It's because your handler must have the same signature specified by the EventHandler delegate.
That is, you'll have to remove your two middle parameters:
private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{
}
In terms of a workaround for passing these parameters into the function, you have a few options...
Generate the event handler as an anonymous function (as per James' answer)
Store and retrieve them from instance variables
Store them on the DateTimePicker control's Tag property and resolve them in the handler
The second option should be obvious enough...
The third option might look like:
// In control initialization somewhere
dateTimePicker1.Tag = new DateTimePickerParams() { Series = myseries, Multiplier = multiplier }; // Where DateTimePickerParams is your own private class/struct defined explicitly for this purpose...
private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{
var ctl = sender as DateTimePicker;
var parameters = ctl.Tag as DateTimePickerParams;
var mySeries = parameters.Series;
var multiplier = parameters.Multiplier;
// Execute...
}
You can't add arbitrary parameters to the event handler like that, the method signature must match the event delegate. How would the DateTimePicker know what to pass for the myseries and multiplier parameters?