I am trying to fire an touchupinside event of Uibutton programmatically. How can i do that ? The code I tried uses PerformSelector but i get this error
"Error MT4117: The registrar found a signature mismatch in the method
'VCPAckage2.ActivityViewController.TouchUpInsideEvent' - the
selector 'TouchUpInsideEvent:' indicates the method takes 1
parameters, while the managed method has 2 parameters. "
I want to achieve something like
UIButton.FireEvent("TouchUpInsideEvent") - this will fire the TouchUpInsideEvent
UIButton.PerformSelector(new MonoTouch.ObjCRuntime.Selector ("TouchUpInsideEvent:"), null, 2000f);
Here's the code
private void LoadFn()
{
UIButton btnSubmit = new UIButton(new RectangleF(0,0,View.Frame.Width,40));
btnSubmit.TouchUpInside+=TouchUpInsideEvent;
}
[Export("TouchUpInsideEvent:")]
private void TouchUpInsideEvent(object sender,EventArgs e){
float yy = AppConstants.ZeroVal;
if (FeedbackSubmittedReturnFlag == true) {
yy = ChildScrollView2.Subviews[1].Frame.Height+ChildScrollView2.Subviews[1].Frame.Y;
}
this.ParentScrollView.SetContentOffset (new PointF (View.Frame.Width, yy), false);
}
The following code snippet would be suffice
btnObj.SendActionForControlEvents(UIControlEvent.TouchUpInside);
It has to be called from Main thread
There's a few different things above.
First, the MT4117 is correct. It happens because your [Export] attribute specify a selector to a method that has only one parameter (i.e. it has only one :) while the managed method has two parameters (which is the default for .NET events). The registrar will spot such conditions and report errors.
Second, the PerformSelector methods are bindings over performSelector:... selectors (most are defined on the NSObject protocol, not class). As such they have the same limitations (e.g. the number of arguments they can handle).
Third, there are several ways you could call your own code. An easy one would be, like #jonathanpeppers suggested, to directly call your managed method when needed.
Another one would be to adjust your code to match both 1 and 2 requirements, e.g.
// assign one (two parameters) method as a .NET event
btnSubmit.TouchUpInside += TouchUpInsideEvent;
...
// call another (one parameter) method like a selector
any_nsobject.PerformSelector (new Selector ("TouchUpInsideEvent:"), sender as NSObject, 0f);
...
// have the 2 parameters method call the(1 parameter) export'ed method
private void TouchUpInsideEvent (object sender, EventArgs e)
{
TouchUpInsideEvent (sender as NSObject);
}
[Export ("TouchUpInsideEvent:")]
private void TouchUpInsideEvent (NSObject sender)
{
Console.WriteLine ("yay!");
}
Related
How to add extra parameters to the following callback :
objXmpp.OnLogin += new ObjectHandler(objXmppArun_OnLogin);
private void objXmppArun_OnLogin(object sender)
{
}
Is it possible to send one extra parameter to the objXmppArun_OnLogin event handler?
No, it's not possible. Events (and delegates in general) in C# define a specific method signature with fixed parameters, so you cannot add extra ones.
The best thing to do is create a separate method which your event handler can call and pass the extra parameter to:
objXmpp.OnLogin += new ObjectHandler(objXmppArun_OnLogin);
private void objXmppArun_OnLogin(object sender)
{
LoginCheck(sender, "Some Info");
}
private void LoginCheck(object sender, string extraParameter)
{
// do your thing here
}
Or if the value you need is only known when you attach the handler, you can wrap it up in an anonymous method:
private void AttachHandlers()
{
string parameter = "Some Info";
objXmpp.OnLogin += new ObjectHandler(sender => {
objXmppArun_OnLogin(sender, parameter);
});
}
private void objXmppArun_OnLogin(object sender, string extraParameter)
{
}
You cant change the delegate expected by whatever component you're using (objXmpp.OnLogin) so you therefore cant change the parameters that you handler method expects.
However, that handler has access to properties & methods of the class it is within, just like any normal method would.
(You might like to update youre question to what you're trying to achieve rather than how you're trying to achieve it - you might be able to get a better answer)
I have a ton on controls on a form, and there is a specific time when I want to stop all of my events from being handled for the time being. Usually I just do something like this if I don't want certain events handled:
private bool myOpRunning = false;
private void OpFunction()
{
myOpRunning = true;
// do stuff
myOpRunning = false;
}
private void someHandler(object sender, EventArgs e)
{
if (myOpRunning) return;
// otherwise, do things
}
But I have A LOT of handlers I need to update. Just curious if .NET has a quicker way than having to update each handler method.
You will have to create your own mechanism to do this. It's not too bad though. Consider adding another layer of abstraction. For example, a simple class called FilteredEventHandler that checks the state of myOpRunning and either calls the real event handler, or suppresses the event. The class would look something like this:
public sealed class FilteredEventHandler
{
private readonly Func<bool> supressEvent;
private readonly EventHandler realEvent;
public FilteredEventHandler(Func<bool> supressEvent, EventHandler eventToRaise)
{
this.supressEvent = supressEvent;
this.realEvent = eventToRaise;
}
//Checks the "supress" flag and either call the real event handler, or skip it
public void FakeEventHandler(object sender, EventArgs e)
{
if (!this.supressEvent())
{
this.realEvent(sender, e);
}
}
}
Then when you hook up the event, do this:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
When WhateverEvent gets raised, it will call the FilteredEventHandler.FakeEventHandler method. That method will check the flag and either call, or not call the real event handler. This is pretty much logically the same as what you're already doing, but the code that checks the myOpRunning flag is in only one place instead of sprinkled all over your code.
Edit to answer question in the comments:
Now, this example is a bit incomplete. It's a little difficult to unsubscribe from the event completely because you lose the reference to the FilteredEventHandler that's hooked up. For example, you can't do:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
//Some other stuff. . .
this.Control.WhateverEvent -= new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler; //Not gonna work!
because you're hooking up one delegate and unhooking a completely different one! Granted, both delegates are the FakeEventHandler method, but that's an instance method and they belong to two completely different FilteredEventHandler objects.
Somehow, you need to get a reference to the first FilteredEventHandler that you constructed in order to unhook. Something like this would work, but it involves keeping track of a bunch of FilteredEventHandler objects which is probably no better than the original problem you're trying to solve:
FilteredEventHandler filter1 = new FilteredEventHandler(() => myOpRunning, RealEventHandler);
this.Control.WhateverEvent += filter1.FakeEventHandler;
//Code that does other stuff. . .
this.Control.WhateverEvent -= filter1.FakeEventHandler;
What I would do, in this case, is to have the FilteredEventHandler.FakeEventHandler method pass its 'this' reference to the RealEventHandler. This involves changing the signature of the RealEventHandler to either take another parameter:
public void RealEventHandler(object sender, EventArgs e, FilteredEventHandler filter);
or changing it to take an EventArgs subclass that you create that holds a reference to the FilteredEventHandler. This is the better way to do it
public void RealEventHandler(object sender, FilteredEventArgs e);
//Also change the signature of the FilteredEventHandler constructor:
public FilteredEventHandler(Func<bool> supressEvent, EventHandler<FilteredEventArgs> eventToRaise)
{
//. . .
}
//Finally, change the FakeEventHandler method to call the real event and pass a reference to itself
this.realEvent(sender, new FilteredEventArgs(e, this)); //Pass the original event args + a reference to this specific FilteredEventHandler
Now the RealEventHandler that gets called can unsubscribe itself because it has a reference to the correct FilteredEventHandler object that got passed in to its parameters.
My final advice, though is to not do any of this! Neolisk nailed it in the comments. Doing something complicated like this is a sign that there's a problem with the design. It will be difficult for anybody who needs to maintain this code in the future (even you, suprisingly!) to figure out the non-standard plumbing involved.
Usually when you're subscribing to events, you do it once and forget it - especially in a GUI program.
You can do it with reflection ...
public static void UnregisterAllEvents(object objectWithEvents)
{
Type theType = objectWithEvents.GetType();
//Even though the events are public, the FieldInfo associated with them is private
foreach (System.Reflection.FieldInfo field in theType.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))
{
//eventInfo will be null if this is a normal field and not an event.
System.Reflection.EventInfo eventInfo = theType.GetEvent(field.Name);
if (eventInfo != null)
{
MulticastDelegate multicastDelegate = field.GetValue(objectWithEvents) as MulticastDelegate;
if (multicastDelegate != null)
{
foreach (Delegate _delegate in multicastDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(objectWithEvents, _delegate);
}
}
}
}
}
You could just disable the container where all these controls are put in. For example, if you put them in a GroupBox or Panel simply use: groupbox.Enabled = false; or panel.Enabled = false;. You could also disable the form From1.Enabled = false; and show a wait cursor. You can still copy and paste these controls in a container other than the form.
I think this article has the same problem with me. However, there's no workable solution for my case.
I'm using Windows Media Player ActiveX in my program.
For some reason, I don't want to add a reference of it and convert to AxHost automatically by IDE.
I create the instance by Activator and ProgID
protected const string WMP_PROG_ID = "WMPlayer.OCX.7";
private dynamic _wmp;
protected virtual bool init(){
try{
_wmp = Activator.CreateInstance(Type.GetTypeFromProgID(WMP_PROG_ID));
}
catch{ return false; }
return true;
}
I was tried to do this by Reflection, but I found that dynamic is suitable to my case.
Every property and method works alright, like these:
protected override bool setSpeed(float speed){
try{
_wmp.settings.rate = speed;
}
catch { return false; }
return true;
}
protected override int getLength(){
double res;
try{
res = _wmp.currentMedia.duration;
}
catch { return 0; }
return (int)(res * 1000);
}
Unfortunately, when I want to attach event like the article I indicated in the top, it got no work.
My code like this:
protected bool connectEvent(){
_wmp.StatusChange += new EventHandler(_wmp_StatusChange);
return true;
}
protected void _wmp_StatusChange(object sender, EventArgs e){
Console.WriteLine(_wmp.Status);
}
I've checked the type of event handler of StatusChange, it's EventHandler.
These codes compiled well, and I can load some music, play it, pause it, ...do anything I like.
But the StatusChange event never triggered.
I tried to set a break-point at connectEvent.
When run at _wmp.StatusChange += new EventHandler(...), the IntelliTrace give me some information.
Those information had written in Trad. Chinese, I think it means:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Could not apply operator "+=" to type System.Dynamic.DynamicObject and System.EventHandler
Even though there's an exception, but just like I said, compile was passed, everything still work -- except I could not listen event.
So, how can I attach event successfully in the dynamic object _wmp?
Any possible solution (like Reflection) is useful to me.
Also, in the case above, the handler type of StatusChange is EventHandler.
But if I want to handle PlayStateChange event, it is an "Unknown handle" if I don't add a reference of wmp.dll.
I hope the solution is suitable to this case, too.
Thanks everyone in advance for all of your support, and please forgive me for my poor English.
The generic strategy to turn a program that uses a COM object from early bound to late bound calling is to first write it early bound. IntelliSense will help you fall in the pit of success, ensuring that you use correctly named methods, pass the right kind of arguments and particularly useful to help you find out what the event handler signatures should look like.
Which produces this bit of test code:
void testEarlyBound() {
var wmp = new WMPLib.WindowsMediaPlayer();
wmp.StatusChange += new WMPLib._WMPOCXEvents_StatusChangeEventHandler(wmp_StatusChange);
}
void wmp_StatusChange() {
throw new NotImplementedException();
}
With the StatusChange event handler assignment and method body completely auto-generated by IntelliSense. Note the signature of the event handler, it is not an EventHandler. Just a method that returns void and takes no arguments, it matches the Action delegate type. Now you have a good shot at writing the late-bound version without the undiagnosable runtime exceptions:
void testLateBound() {
dynamic wmp = Activator.CreateInstance(Type.GetTypeFromProgID("WMPlayer.OCX"));
wmp.StatusChange += new Action(wmp_StatusChange);
}
I have the following Interface Declaration:
public interface IBasePresenter
{
void Run();
void ShowDialog<T, M>(T t, M m ) where T : UserControl where M : Form, ISomeInterface<SomeType>;
}
The ShowDialog() is basically a method that will show a modal dialog box to the user. Where 'T' is the parent Form and M is the unique dialog to show. M of which there are multiple different types! Hence the reason to choose a generic method!
A couple of ways I think this method could be used:
Presenter.ShowDialog(this, typeof(Form1)); // FigA
Or
Presenter.ShowDialog(this, new Form1()); // FigB
Based upon Fig A or B, what exactly will a sample ShowDialog() method implementation look like?
My questions stems from trying to figure how the generic parameter 'M' is instantiated inside of a ShowDialog() method implementation.
At a guess:
m.Controls.Add(t);
m.ShowDialog();
However, frankly I'm not sure this utility method adds much useful, and it could just as well be non-generic (void ShowDialog(Control t, Form m)). It could perhaps be more useful if using the : new() constraint, which would also avoid the risk of using the same control instance on multiple forms (illegal). But as I say: frankly I wouldn't bother with this method until it had demonstrated some non-trivial usefulness. And if I did keep it, I'd rename the parameters to be more illuminating; none of M, m, T, t tell me what they mean.
You cannot use the Fig A way because typeof(Form1) is a System.Type, not a Form; the code will not compile unless there is an overload that takes a second parameter of type System.Type.
how the generic parameter 'M' is instantiated inside of a ShowDialog() method implementation?
It is not "instantiated" it is "inferred:. You provided the instance already; the compiler infers the type from the invocation.
You could change the generic method signature as follows:
public void ShowDialog<T>() where T : Form, new() {
using(var dialog = new T()){
dialog.ShowDialog();
}
}
and then the call:
ShowDialog<MyCoolDialog>();
would result in the mtheod creating (not inferring this time ;)) a new instance of the form and showing it in a modal way.
Below is an slightly updated version of the interface method:
void ShowDialog<TParentForm, TDialogForm, TModel, TEntity>(TParentForm t, TDialogForm m, Action callback)
where TParentForm : UserControl
where TModel : class, IModel<TEntity>, new()
where TDialogForm : Form, IEditableItem<TEntity>, new();
I made some assumptions on the previous version so during my testing and refinement phase the method signature has changed. It's still more or a less a en educational exercise for me so I still wanted to know how to pull it off rather than simple chose the easy way out.
A sample implementation of the method:
public void ShowDialog<TParentForm, TDialogForm, TModel, TEntity>(TParentForm t, TDialogForm m, Action callback)
where TParentForm : UserControl
where TModel : class, IModel<TEntity>, new()
where TDialogForm : Form, IEditableItem<TEntity>, new()
{
using (var dialogToShow = new TDialogForm())
{
dialogToShow.StartPosition = FormStartPosition.CenterScreen;
dialogToShow.FormBorderStyle = FormBorderStyle.FixedSingle;
dialogToShow.Model = new TModel();
// 2. show the new user control/form to the user.
var result = dialogToShow.ShowDialog(t);
// 3. handle the dialog result returned and update the UI appropriately.
if (result == DialogResult.OK)
{
// print status label.
callback.Invoke();
}
}
}
I am not entirely sure why the 'TDialogForm m' parameter is still in there as it does not seem to be used anywhere.
How to use the method:
private void BtnAddNewServiceClick(object sender, EventArgs e)
{
Presenter.ShowDialog<ServerRolesControl, AddNewServiceForm, ServiceModel, Role>(this, new AddNewServiceForm(), SetAddedRolesLabel);
}
private void BtnViewAllServicesClick(object sender, EventArgs e)
{
Presenter.ShowDialog<ServerRolesControl, ViewRolesForm, ServiceModel, Role>(this, new ViewRolesForm(), SetDeletedRolesLabel);
}
I should update the interface method but it was so much pain getting it to work I would rather leave it alone now =).
How can I call this method programmatically?
If I simple do KillZombies(), it says I don't have the correct parameters, but I don't know what parameters to specify when I'm just using code...
public static void KillZombies(object source, ElapsedEventArgs e)
{
Zombies.Kill();
}
Have you tried:
KillZombies(null, null);
Perhaps refactor your design:
public static void KillZombies(object source, ElapsedEventArgs e)
{
//more code specific to this event, logging, whathaveyou.
KillSomeZombies();
}
public static void KillSomeZombies()
{
Zombies.Kill();
}
//elsewhere in your class:
KillSomeZombies();
KillZombies(null, null);
However, I would question whether that's a good design.
You'd have to create the parameters and pass them through too. Why not just call the function directly by putting it in another function that is available for other classes to call? It'll make for much neater design.
i.e.
internal void MakeZombiesKill()
{
Zombies.Kill();
}
?
Your method signature requires two arguments. You cannot just call KillZombies(), you will need to pass the correct arguments to the method.
KillZombies(source, e);
If you do not have your source or e, you can simply pass null.
KillZombies(null, null);
You usually use the object from inside which you call the method as source (or null if static).
And set the ElapsedEventArgs to something relevant for the method. For ElapsedEventArgs it would be something like: new ElapsedEventArgs() { SignalTime = DateTime.Now}
KillZombies(this, new ElapsedEventArgs() { SignalTime = DateTime.Now});
If you don't really use source or e inside the method you can call it with null arguments.
KillZombies(null, null);
Technically speaking, you should be separating out the task from inside the event handler and have the event handler call the method containing the code you want run, this way you can call that code without tripping the event handler. However, if you want to trip the event handler programmatically:
KillZombies(this, new ElapsedEventArgs())
I however would break it out as is a frequently used best practice...