I'm trying to use the DecelerationEnded callback in conjunction with 'Tapped' callbacks on MT.Dialog elements. I can't get the two to work at the same time.
When the DecelerationEnded callback is commented out, the 'tapped' callbacks work. When it's commented in, the 'tapped' callbacks don't get triggered anymore (whereas DecelerationEnded does).
When the DecelerationEnded call is moved above the setting of the Root, then the button 'tapped' callbacks work, but the DecelerationEnded callback doesn't. Delaying the callback setup until ViewWillAppear also doesn't fix anything.
Any solutions?
Example code:
public class TestController : DialogViewController
{
public TestController () : base(UITableViewStyle.Plain, null, true)
{
// Create list of 20 buttons.
Section s = new Section();
for (int i = 0; i < 20; i++ )
{
s.Add(new StringElement("test " + i, () => {
Console.WriteLine("Tapped"); // Tapped callback.
}));
}
Root = new RootElement("Test") {s};
// The following line causes all the "tapped" handlers to not work.
this.TableView.DecelerationEnded += HandleDecelerationEnded;
}
void HandleDecelerationEnded (object sender, EventArgs e)
{
Console.WriteLine ("Deceleration Ended");
}
}
In MonoTouch you can use either the C# style of callbacks or the Objective-C style of callbacks, but they can not be mixed together:
http://docs.xamarin.com/ios/advanced_topics/api_design#Delegates
Internally the MonoTouch.Dialog library implements its features by providing a full subclass that handles all of the events. If you use the C# syntax, it replaces the built-in handler with a proxy that in this case, merely responds to DecelerationEnded.
If you want to hook up to this, you need to subclass the existing "Source" class, and create this by overriding the CreateSizingSource, and it should provide a new instance of your class. This is the virtual method that you need to override to provide the same behavior but with your own classes:
public virtual Source CreateSizingSource (bool unevenRows)
{
return unevenRows ? new SizingSource (this) : new Source (this);
}
You can just subclass SizingSource and override the method there for the deceleration method.
TweetStation has a sample that shows how this is done: it uses the same event to determine when to remove the number of unread tweets from the screen.
Related
I know you don't understand the question title. Let me tell you the whole scenario.
I have a class named as Processor. Processor can get notifiable steps or send notification to other application API depending on some condition. Like as below:
Method: SendOrStartProcess(Operation operation)
Method Implementation:
If(operation.steps.any(o=>o.canProcess)){
_service.notify(operations); //This is fine
}
else{
var totalSteps = await _service.getAdjustableSteps(); //It returns the adjustable steps and will invoke event which is subscribed by another class named as GetAdjustableStepsEnd. It can be invoked immediately or after some time.
//Set totalSteps in operationsc.steps and save in database and that's it.
}
Now, I have another class named as "OperationHandler" which subscirbed the GetAdjustableStepsEnd event.
public OperationHandler(IUnityContainer container)
{
_agent.GetAdjustableStepsEnd += GetAdjustableStepsEnd ;
}
public async void GetAdjustableStepsEnd (object sender, GetAdjustableStepsEndEventArgs e)
{
// Here i will call again the above method _processor.SendOrStartProcess(e.Operations);
}
//Now the problem is if event invokes after some time then it is fine because meanwhile i set the status in database. But if it invoked just after the getAdjustableSteps then i call SendOrStartProcess again and it sends getAdjustableSteps again because record is not set in the database. How to overcome this situation. I can not put lock on it because this is used by many clients.
For a game I'm developing I'm keeping track of a GameState to determine which systems should be active. To enable systems to register themselves to State changes, I've written the following code:
public static Action<State> OnDefaultStateChange;
public static Action<State> OnConstructionStateChange;
private static Dictionary<GameState, Action<State>> _stateChangeActions =
new Dictionary<GameState, Action<State>>()
{
{GameState.Default, OnDefaultStateChange},
{GameState.Construction, OnConstructionStateChange}
};
When a state is changed, it invokes the relevant action by looking up the GameState key in the _stateChangeActions dictionary.
Here's the strange behaviour that I can't understand.
If I subscribe to the action by using _stateChangeActions[key] += ListenerMethod;, it invokes correctly. But if I subscribe on the public static field, e.g OnDefaultStateChange += ListenerMethod;, and I invoke the action through the dictionary, it's as if there are no listeners.
I haven't been able to find out why this happens. Note: I'm using Unity Engine, and this issue isn't blocking me, I'm just curious.
Answer to your question
OnDefaultStateChange and _stateChangeActions have no relation to each other, other than the fact you use OnDefaultStateChange to initialize _stateChangeActions.
Your line with {GameState.Default, OnDefaultStateChange}, adds the object inside OnDefaultStateChange to the dictionary and not the reference, which means that _stateChangeActions[GameState.Default] is not the same as OnDefaultStateChange.
An example to show what is actually going on in your setup:
var state = new { LivesLeft = 2, ShirtColor = "brown" };
// Corresponds to 'OnDefaultStateChange'
Action<State> someAction = (s) =>
{
Console.WriteLine("Lives: " + s.LivesLeft);
};
// Corresponds to '_stateChangeActions'
Action<State> copyOfSomeAction = someAction;
// Subscribe to "OnDefaultStateChange"
someAction += (s) =>
{
Console.WriteLine("Shirt color: " + s.ShirtColor);
};
// 'someAction' is longer equal to 'copyOfSomeAction' since 'someAction'
// has been replaced with a new Action which produces the result from two other
// Actions.
someAction(state);
// Output:
// Lives: 2
// Shirt color: brown
copyOfSomeAction(state);
// Output:
// Lives: 2
As you can see OnDefaultStateChange and _stateChangeActions works as two independent objects, so "subscribing" to OnDefaultStateChange doesn't make that new subscriber available to _stateChangeActions.
How to solve your issue
I would suggest you make use of the event features in C#. I'm guessing a little on how you actually check the type of event to fire, but your event handling class could look something like this:
// MyEventHandlerClass.cs
public delegate void StateChangedEventHandler(object sender, State state);
public static event StateChangedEventHandler DefaultStateChanged;
public static event StateChangedEventHandler ConstructionStateChanged;
private static FireNewStateChangeEvent(State state) {
switch (state.StateChangeType)
{
case GameState.Default:
DefaultStateChanged.Invoke(this, state);
case GameState.Construction:
ConstructionStateChanged.Invoke(this, state);
}
}
To subscribe to events you simply do pretty much like you already do:
MyEventHandlerClass.DefaultStateChanged += ListenerMethod;
With this setup you can subscribe or unsubscribe (-=) to events from wherever.
I am developing a MEF application. I am using a plugin as a publisher and another as a subscriber. For the current issue I guarantee that both plugin instances are active. On the subscriber I subscribe to the event and on the publisher I iterate over the invocation list and call the BeginInvoke to raise the event asynchronously as so:
Publisher:
public class BackchannelEventArgs : EventArgs {
public string Intensity { get; }
public BackchannelEventArgs(string intensity) {
this.Intensity = intensity;
}
}
public class Publisher {
public event EventHandler<BackchannelEventArgs> BackchannelEvent = delegate { };
private void BackchannelEventAux(string bcintensity) {
Plugin.LogDebug("BACKCHANNEL EVENT, sending to " + BackchannelEvent.GetInvocationList().Length + " subscribers: " + bcintensity);
var args = new BackchannelEventArgs(bcintensity);
foreach (EventHandler<BackchannelEventArgs> receiver in BackchannelEvent.GetInvocationList()) {
receiver.BeginInvoke(this, args, null, null);
}
}
}
Subscriber (relevant snippet, the Init is being called by a pluginsManager in which I can see the logs):
class Subscriber {
public void Init(){
LogInfo("Before subscribing");
publisher.BackchannelEvent += HandleBackchannelEvent;
LogInfo("After subscribing");
}
private void HandleBackchannelEvent(object sender, BackchannelEventArgs e) {
LogDebug("Handle Backchannel!");
}
}
Now, the Log you see on the event handler is not called at all. I have 4 other events that follow the same structure and somewhat this event in particular is not being called (I can see the logs on the other events). The other plugins follow the exact same structure.
Already tried:
Call synchronously BackchannelEvent(this, args) but the results are the same;
Subscribe this same event on the other plugins as well but the issue remains on this single event (and not on the others who follow the same structure).
I hope you can give me some help on this.
Thank you
Edit: The shown code is a snippet. The Init method is being called by the pluginsManager. I have put a log before the subscribing call and I can confirm that I am indeed subscribing.
Edit2: The number of elements in the InvocationList is in fact 2 (the empty delegate and the subscriber) so it checks out.
Okay. I don't know why but I figured out the solution so that other ones who stumble with the issue can find a solution. It was related with a extension I created for the Random class (which wasn't throwing a exception although... so it might be a bug on C#, I can't really explain). The Random extension is provided by an external NuGet package I created.
Version A (without using the Random Extension):
Body of the EventHandler:
LogDebug("Inside Handler");
double intensityValue2 = GetRandomNumber(Settings.MinimumIntensity, Settings.MaximumIntensity);
double frequency2 = GetRandomNumber(Settings.MinimumFrequency, Settings.MaximumFrequency);
int repetitions2 = GetRandomInt(Settings.MinimuMRepetitions, Settings.MaximumRepetitions);
Version B (using Random extension):
Body of EventHandler:
LogDebug("Inside Handler");
double intensityValue2 = random.GetRandomNumber(Settings.MinimumIntensity, Settings.MaximumIntensity);
double frequency2 = random.GetRandomNumber(Settings.MinimumFrequency, Settings.MaximumFrequency);
int repetitions2 = random.GetRandomNumber(Settings.MinimuMRepetitions, Settings.MaximumRepetitions);
Version A is the one that it is working. The Logs are guaranteed to appear. I don't know why it isn't letting me use extensions but it is solved for now. It would make sense if the Random extension threw an exception but it is not the case...
If any other person stumbles upon the issue I hope this helps you figure out the issue faster than me.
Thank you
Edit: typo
This may have been asked several times, but I don't know what to search for..
Anyway. I have a class called Character. Inside of it I want to have a collision component that I have called RectangleCollision. Inside of it there is a function called IsOverlapping that checks for overlap.
I want to have a function that can be modified for each game object. For example create a function called OnBeginOverlap(); that will fire everytime the collision component detects a collision.
Is there any way that I can bind this function as delegate or event? Or something?
You have to read about events and delegates. There are plenty of examples on the web. The easiest I managed to find when I was trying to understand the subject was this:
The Simplest C# Events Example Imaginable
You can also check out the below (you can compile this as console application):
class Character
{
public delegate void OverlappingHandler(Character character, EventArgs e);
public event OverlappingHandler OverlappingEvent;
public void IsOverlapping()
{
bool overlapping = true;
if (overlapping)
{
if (OverlappingEvent != null)
{
OverlappingEvent(this, null);
}
}
}
}
class Program
{
static void Main(string[] args)
{
Character c = new Character();
c.OverlappingEvent += OverlappingEventHandler;
c.OverlappingEvent += OverlappingSecondEventHandler;
c.IsOverlapping();
Console.Read();
}
static void OverlappingEventHandler(Character character, EventArgs e)
{
Console.WriteLine("We have overlapping here!!");
}
static void OverlappingSecondEventHandler(Character character, EventArgs e)
{
Console.WriteLine("Seriously, we have overlapping !!");
}
}
So step by step:
Create a delegate, which is a bridge between your event and the code you want to run when event is triggered. You give parameters to a delegate, which are (object sender, EventArgs e) - in this example sender is the Character class, arguments are used to send additional info - for example type of character.
Create event of our delegate type
In our function IsOverlapping() there would be your logic checking if there is overlapping happening. If there is, you fire up event. You should check first if there is anything connected to the event (hence the if (OverlappingEvent != null)) - if some there is something, fire up the event.
In the Main() you create an instance of the class and...
Subscribe your event handlers to it, so the code that should be executed when the event is triggered. I connected two methods, just to show that you can subscribe more than one.
Now when you run c.IsOverlapping() this is what happens:
your logic to check overlapping runs,
if there is overlapping, there will be a check if OverlappingEvent has code subscribed (it does in Main()),
if it does event will be triggered,
code subscribed to the event runs - in this case your code in Main().
You can compile this as console app and it will display 2 lines:
We have overlapping here!!
Seriously, we have overlapping !!
Hope this helps.
I have a very simple XOML file with a single Code Activity inside the ReceiveActivity Handler.
The ReceiveActivity is mapped to an Interface called IRulesEngineService wih a single method on it.
void DoWork(int i);
the input parameter on the interface method is mapped to a property on the Xoml called I
I'm now trying to attempt to step into the Workflow Life Cycle at a point:
just before the first (and in this case only) Code Activity gets executed
just after the i parameter has been assigned to I on my Workflow.
I've tried overriding all the various methods and events on the XOML but in all cases I is always zero in all the events and overrides I've tried. And then is correctly set to the passed in Parameter within the first Code Activity. e.g. Imagine I passed in 8 to the ClientSide DoWork call.
public int I {get; set;}
protected override void Initialize(System.IServiceProvider provider)
{
I = I*10; //I is still 0
base.Initialize(provider);
I = I * 10; //I is still 0
}
//Event on Xoml Designer
private void Pinnacle_Initialized(object sender, EventArgs e)
{
I = I * 10; //I is still 0
}
//Event on Xoml Designer
private void receiveActivity1_OperationValidation(object sender, OperationValidationEventArgs e)
{
I = I * 10; //I is still 0
}
protected override void OnActivityExecutionContextLoad(IServiceProvider provider)
{
I = I * 10; //I is still 0
base.OnActivityExecutionContextLoad(provider);
I = I * 10; //I is still 0
}
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
DataAccess.WriteToDummyData(ConnectionString, "Pinnacle From Code Activity " + I);
//I is now magically '8' what the heck set this?
}
Anyone got any ideas on where in the Workflow Lifecycle the instantiating/binding/setting of these parameters occurs.
Looking at the .NET framework source code, it's not possible to access your data inputs within the code activity before the execution. in the ReceiveActivity class in the System.Workflow.Activities namespace there's a exact point where the inputs are populated. I've taken the class source from this link
See the image below:
As you can see in the picture inputs are populated at this point:
this.OperationHelper.PopulateInputs(this, requestContext.Inputs);
The instruction above is called just before the ReceiveActivity class executes the activity. At this stage I don't think there's a public event that can be subscribed to manipulate your data before your codeActivity1_ExecuteCode gets executed.
Hope it helps.