how to parse for object sender - c#

I have this method and I have no idea what object sender is sending
void xTreve(object sender, Microsoft.SilverlightMediaFramework.Core.CustomEventArgs<Microsoft.SilverlightMediaFramework.Core.Media.PlaylistItem> e)
{
}
how do I check to see what object sender contains

I'm going to take it that your question is geared toward determining what sort of type sender is so you can work with it.
With that in mind, you would first need to get the type of sender, then you can cast it appropriately so you can operate on it.
For example, you can do the following in your method:
if (sender is TypeA)
{
var iAmA = (TypeA)sender;
// do something A-ish with sender
}
else if (sender is TypeB)
{
var iAmB = (TypeB)sender;
// do something B-ish with sender
}
else
{
// do something else
}
Alternatively, the following does the same as the preceding:
Type type = sender.GetType();
if (type == typeof(TypeA))
{
var iAmA = (TypeA)sender;
// do something A-ish with sender
}
else if (type == typeof(TypeB))
{
var iAmB = (TypeB)sender;
// do something B-ish with sender
}
else
{
// do something else
}

If you need to tell which instance sender is it depends if sender has some kind of property to identify it. Consider the following code:
public void randtest()
{
var rand = new Random();
var obj1 = new object();
var obj2 = new object();
if (rand.Next() % 2 == 1)
{
method(obj1);
}
else
{
method(obj2);
}
}
public void method(object thing)
{
//here i have no way to tell if thing is obj1 or obj2;
}

If the object is always going to be of the same type, but you just aren't sure what that type will be, then set a breakpoint inside the function and use the visual studio quickwatch window to inspect it. You will be able to see the control name and other properties of the sender object, as well as it's type. Once you know the type you know what to cast sender as in the code if you need to manipulate it.

Related

c# Event Creation: Raise vs invoke

Before C#6, i was using this routine to deal with generating events in a multi threaded program: (i found it somewhere, but can't remember where):
public static object Raise(this MulticastDelegate multicastDelegate, object sender, EventArgs e)
{
object retVal = null;
MulticastDelegate threadSafeMulticastDelegate = multicastDelegate;
if (threadSafeMulticastDelegate != null)
{
foreach (Delegate d in threadSafeMulticastDelegate.GetInvocationList())
{
var synchronizeInvoke = d.Target as ISynchronizeInvoke;
if ((synchronizeInvoke != null) && synchronizeInvoke.InvokeRequired)
retVal = synchronizeInvoke.EndInvoke(synchronizeInvoke.BeginInvoke(d, new[] { sender, e }));
else
retVal = d.DynamicInvoke(sender, e);
}
}
return retVal;
}
so all i had to do was Eventname.Raise(...,....)
now with C#6, i know the new was it using something like:
Eventname?.Invoke(...);
what i am wondering is, should i change all my event creations to Invoke as it works different to the Raise(), or is it the same thing ?
You should never have been using that method in the first place. It's way too complicated. Instead, something like this would have been better:
public static void Raise(this Delegate handler, object sender, EventArgs e)
{
if (handler != null)
{
handler.DynamicInvoke(sender, e);
}
}
As for whether you should change your event-raising code, I'd say no. Not unless you've got a lot of time to kill and like going through your entire code base replacing perfectly good code.
What you should do is fix your current Raise() method. And feel free for any new code to write it the new C# 6 way, i.e. MyEvent?.DynamicInvoke(this, EventArgs.Empty) (which effectively amounts to the exact same thing as MyEvent.Raise(this, EventArgs.Empty) using the above, except without the extra method call).

Is there a way to cast an object and access its properties in the same line?

I am talking in the context of event handler in a C# windows forms, but I'm assuming the answer could be used anywhere in C#.
To give an example, I have a form that has many check boxes that each activate a button. The CheckedChanged event is handled by a function that is very similar for each CheckBox and it looks something like this right now:
private void acheckbox_CheckedChanged(object sender, EventArgs e)
{
int uniquetocheckbox = 12345;
if(acheckbox.CheckedChanged)
{
ThisFunction(uniquetocheckbox, true);
AssociatedButton.Enabled = true;
}
else
{
ThisFunction(uniquetocheckbox, false);
AssociatedButton.Enabled = false;
}
}
There are a lot of these check boxes and I'm trying to cut and past the code for each and make as few changes as possible so I want to do something like this :
private void acheckbox_CheckedChanged(object sender, EventArgs e)
{
int uniquetocheckbox = 12345;
if((CheckBox)sender.Checked) //CHANGE HERE
{
ThisFunction(uniquetocheckbox, true);
AssociatedButton.Enabled = true;
}
else
{
ThisFunction(uniquetocheckbox, false);
AssociatedButton.Enabled = false;
}
}
This does not work. The easy work around is this :
private void acheckbox_CheckedChanged(object sender, EventArgs e)
{
int uniquetocheckbox = 12345;
CheckBox cb = (CheckBox)sender;
if(cb.Checked) //CHANGE HERE
{
ThisFunction(uniquetocheckbox, true);
AssociatedButton.Enabled = true;
}
else
{
ThisFunction(uniquetocheckbox, false);
AssociatedButton.Enabled = false;
}
}
But out of pure curiosity I am wondering if there is a way to do it in one line like the second example I gave. I would like to know because I think it looks better and is obviously 1 line shorter.
I think you're just missing a set of parenthesis. You want to cast to Checkbox, then get the properties of that:
if (((CheckBox)sender).Checked)
This will force the order of operations to cast first, then get the property from the cast result.
Sure, it's possible. You just missed another set of brackets:
if(((CheckBox)sender).Checked)
However, I wouldn't do this. Why? You don't want to cast again if you want to access the sender as a textbox again if you did it your way.
You can. For example:
object o;
o = new SomeType();
var prop = ((SomeType)o).SomeProperty;
It needs to be this:
if(((CheckBox)sender).Checked) //CHANGE HERE
But personally I like the way you've shown better. That way if it needs to be casted again, it's already been done.
Don't know any C# but ((CheckBox)sender).Checked) should work. In java the "." (member access) has higher priority than casting so putting the parenthesis like this should force the casting to happen first.
You just need a couple of more parenthesis in your if statement:
if (((CheckBox)sender).Checked)
{
...
}

New instance every time?

In the following code, which is better? To call add page from within CardPanelDesigner_AddPage? Or use the Func TransactionFunction??
Basically I want to know if doing the inner func will create a "new function" every time :S I don't even know what I'm asking.
Is there an overhead to doing the inner function or should I use the addpage?
private object AddPage(IDesignerHost Host, object Sender)
{
return null;
}
private void CardPanelDesigner_AddPage(object sender, EventArgs e)
{
IDesignerHost DesignerHost = (IDesignerHost)GetService(typeof(IDesignerHost));
if (DesignerHost != null)
{
Func<IDesignerHost, object, object> TransactionFunction = (Host, Param) =>
{
return null;
};
TransactionInfo("Add Page", DesignerHost, AddPage); //Add page? OR TransactionFunction? :S
}
}
Yes, TransactionFunction will create a new object each time CardPanelDesigner_AddPage is called. The performance overhead of this however will likely be negligible. You should do whatever reads best to you (and your team).

Background worker run worker completed

depending on the do work method my result could either be a List of Strings or a list of byte[]
How can we check the RunWorkerCompletedEventArgs e -
if (e is List<String>)
is this the correct way to check?
No, this is not the right way.
The correct way is to use this:
if(e.Result is List<string>)
{
//...
}
else if(e.Result is List<byte[]>)
{
//...
}
else
{
//...
}
e will always be of type RunWorkerCompletedEventArgs. But this class contains a property Result that contains the result of your DoWork event handler. That's the one, you need to check.
Yes, that's one possible way to do it.
If you only have two types it would be quite easy:
if(e.Result is List<string>)
{
}
else if(e.Result is List<byte[]>)
{
}
else
{
}
But the problem comes in to play if you have to support more than just two or three. In that case i'm going to create a Dictionary<Type, Action<object>> and write individual functions for each type. Something like this:
var supportedTypes = new Dictionary<Type, Action<object>>();
supportedTypes.Add(typeof(List<string>), ComputeListOfStrings);
supportedTypes.Add(typeof(List<byte[]>), ComputeListOfByteArrays);
private void ComputeListOfString(object listOfStrings)
{
var list = (List<string>)listOfStrings;
}
private void ComputeListOfByteArrays(object listOfByteArrays)
{
var list = (List<byte[]>)listOfByteArrays;
}
This makes it more simple to support new types and also stays to be O(1) while the if-else-if runs into the order-matters problem.
Used will this in your background worker as followed:
worker.OnRunWorkerCompleted += (sender, e) =>
{
Action<object> supportedAction;
supportedTypes.TryGetValue(e.Result.GetType(), out supportedAction);
if(supportedAction != null)
{
supportedAction();
}
};
the e.Result is the property with your results, so to get the type you can do:
if(e.Result.GetType().Equals(typeof(List<String>)))

passing values between forms (winforms)

Wierd behaviour when passing values to and from second form.
ParameterForm pf = new ParameterForm(testString);
works
ParameterForm pf = new ParameterForm();
pf.testString="test";
doesn't (testString defined as public string)
maybe i'm missing something? Anyway I'd like to make 2nd variant work properly, as for now - it returns null object reference error.
Thanks for help.
Posting more code here:
calling
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(doc.GetElementById(ParametersButton.Tag.ToString()));
pf.ShowDialog(this);
pf.test = "test";
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
};
definition and use
public partial class ParameterForm : Form
{
public string test;
public XmlElement node;
public delegate void ParameterSubmitResult(object sender, XmlElement e);
public event ParameterSubmitResult Submit;
public void SubmitButton_Click(object sender, EventArgs e)
{
Submit(this,this.node);
Debug.WriteLine(test);
}
}
result:
Submit - null object reference
test - null object reference
pf.ShowDialog(this); is a blocking call, so pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit); is never reached: switch the order.
Submit(this,this.node); throws a null object reference because no event is assigned to it (see above). Generally, you should always check first: if (Submit != null) Submit(this,this.node);
You should change ``pf.ShowDialog(this);topf.Show(this);` so that your main form isn't disabled while your dialog box is open, if that's what you want, or use the model below (typical for dialog boxes.)
I'm not sure what pf_Submit is supposed to do, so this might not be the best way to go about it in your application, but it's how general "Proceed? Yes/No" questions work.
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(testString);
pf.ShowDialog(this); // Blocks until user submits
// Do whatever pf_Submit did here.
};
public partial class ParameterForm : Form
{
public string test; // Generally, encapsulate these
public XmlElement node; // in properties
public void SubmitButton_Click(object sender, EventArgs e)
{
Debug.WriteLine(test);
this.Close(); // Returns from ShowDialog()
}
}
When you want to use your second variant, you have to use a getString()-Method, where you can put the e.g. "testString". The way you wrote it, "testString" should be a method (and got brackets).
EDIT (a bit more precise):
You could write:
pf.getString(testString);
, if "pf" is an instance of your own class, otherwise you had to look up, whether you can retrieve a String in this class.
the thing was in line order :)
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
and
pf.Test = "test";
should have been set before
pf.ShowDialog(this);
my mistake thingking that parameter can be passed after 2nd form was displayed
thnx for answers

Categories