1

In my WPF program, I need to set aircraft failure for a flight simulation software. For example, if I click "Fire Engine 1" button on MainWindow,

    private DispatcherTimer DT;

    private void button_Engine_1_On_Fire(object sender, RoutedEventArgs e)
    {
        SettingFailureCondition("Fire engine 1");
    }

Then a pop-up window instance "ftc" will show up for user to set the condition to trigger the failure

    private void SettingFailureCondition(string failure_name)
    {
      FailureTriggerCondition ftc = new FailureTriggerCondition();
      ...
      if (ftc.ShowDialog() == true)
      {
         if(altitude>input)//if the altitude in the software higher than user's input
         {
            DT.Tick += new EventHandler((sender, e)=>MoveFailureByFlag(failure_name, flag));
            DT.Interval = new TimeSpan(0, 0, 0, 1);
            DT.Start();
            DT.Tick -= new EventHandler((sender, e)=>MoveFailureByFlag(failure_name, flag));//Why can't this unsubscribe the event?
         }
      }
    }

As for the above code, I need to detect if the altitude meets the requirement once per second. But once it is met, execute MoveFailureByFlag and stop detecting it. How to do it?

if(altitude>input)//once this is met, execute function MoveFailureByFlag then stop detecting it  

I am thinking about unsubscribing the event but can't find a way in this case. The following fails but I don't know why.

DT.Tick -= new EventHandler((sender, e)=>MoveFailureByFlag(failure_name, flag));//Why can't this unsubscribe the event?

Thanks for any help.

Jeff
  • 27
  • 7
  • You are mixing simulation code with UI code. Bad Idea. But your problem is, you do the check outside the event handler. You need to do it inside the handler, too. And again, that would be much easier if your simulation code was separate module with a common simulation data set. – Fildor Jan 04 '18 at 09:28
  • Thanks. To separate them is not easy for me now. If I do the if statement inside function "move_failure_by_flag" (is it what you mean?), I still have no way to stop detecting it. @Flidor – Jeff Jan 04 '18 at 09:59
  • I think I misunderstood. So you want to stop executing `move_failure_by_flag` as soon as altitude drops below input? In that case you should stop the DT and maybe clear the Tick event handler. You could do this inside the move_failure_by_flag if you pass DT itself to it. – Fildor Jan 04 '18 at 10:03
  • take a look here https://stackoverflow.com/a/91853/5605739 – Celso Lívero Jan 04 '18 at 10:06
  • What I want is only to detect the altitude and do nothing else when altitude is below input. Then I want to execute move_failure_by_flag and stop detecting the altitude as soon as altitude is over input. Therefore move_failure_by_flag is not triggered until the altitude meet the requirement, and once it is triggered (it will only be triggered once), the whole procedure ends. @Fildor – Jeff Jan 04 '18 at 10:11
  • The corresponding requirement is that I am setting a pending failure - "Engine 1 on Fire", the trigger condition is that the altitude is over 5,000 feet. So once the aircraft ascends to over 5,000 feet, the engine starts to be on fire. Then I don't need to detect the altitude any more and don't need to set this failure again. Is it clear? Thanks. @Flidor – Jeff Jan 04 '18 at 10:22
  • It is not clear why you can't simply remove it from a list of pending failures. And make enabling the timer conditional on the Count. Do not dynamically add the event handler, that is a lot of trouble. Micro-optimizing in a simulation or game is not a feature btw, consistency is much more important. – Hans Passant Jan 04 '18 at 10:50
  • Now I use DT.stop() in function move_failure_by_flag. The 1st time it works fine, the 2nd time move_failure_by_flag execute multiple times, the 3rd time it executes even more times. I don't know what causes this. And what do you mean by "dynamically add the event handler"? Thanks. @Hans Passant – Jeff Jan 05 '18 at 03:22
  • That happens because you keep adding the event handler. Do it just once. – Hans Passant Jan 05 '18 at 05:05
  • Yes I am keep adding the event handler. I do it every time when I need to set a pending failure, i.e. the trigger condition of this event is if (ftc.ShowDialog() == true). How do I do it once only or where do I unsubscribe it? @Hans Passant – Jeff Jan 05 '18 at 05:28
  • As an aside, I'd strongly recommend starting to follow .NET naming conventions. – Jon Skeet Jan 05 '18 at 07:25
  • Hello, I don't quite understand. Can you specify it? @Jon Skeet – Jeff Jan 05 '18 at 07:40
  • Well you've got names like `move_failure_by_flag` which would conventionally be `MoveFailureByFlag`. See https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/general-naming-conventions – Jon Skeet Jan 05 '18 at 07:52
  • OK, thanks for this valuable suggestion. I will follow it. @Jon Skeet – Jeff Jan 05 '18 at 07:54

1 Answers1

2

Let me answer your general question first:

DT.Tick += new EventHandler((sender, e)=>MoveFailureByFlag(failure_name, flag));
...
DT.Tick -= new EventHandler((sender, e)=>MoveFailureByFlag(failure_name, flag));//Why can't this unsubscribe the event?

These don't correspond, because they are two different event handlers (note the new keyword).

You can, however, save your event handler in a variable and use that to unsubscribe it:

EventHandler myHandler = new EventHandler((sender, e)=>MoveFailureByFlag(failure_name, flag));

DT.Tick += myHandler;
...
DT.Tick -= myHandler;

In your specific code example, however, you will remove the event handler before the event has had time to occur, so no event will happen at all.

If you want to remove the handler after the event has occurred for the first time, you can use a "self-removing" event handler:

EventHandler myHandler;

myHandler = new EventHandler((sender, e) =>
{
    MoveFailureByFlag(failure_name, flag);
    DT.Tick -= myHandler;
});
DT.Tick += myHandler;
DT.Interval = ...;
DT.Start();
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • Yes, thank you. And "DT.Tick -= myHandler" should be inside MoveFailureByFlag(failure_name, flag) – Jeff Jan 05 '18 at 08:38
  • @Jeff: Or at least inside the lambda expression, see the update to my answer. – Heinzi Jan 05 '18 at 08:38
  • Oh, thanks. You help me find the reason the event doesn't happen is that it has no time. @Heinzi – Jeff Jan 05 '18 at 08:56