定时器触发的带参数的事件怎样取消订阅?

weixin_37698796 2018-01-05 02:05:40
我在WPF中需要做一个功能,就是在某模拟飞行软件中设置飞机的故障。比如我现在需要设置飞机引擎失火,触发条件是飞机达到5000英尺,那么我需要实时监测飞机的高度,一旦达到5000英尺,则设置引擎失火,不再监测飞机高度。

我有一个窗口让用户来设置触发条件,窗口实例名称叫ftc
if (ftc.ShowDialog() == true)
{
if(...)
{
private DispatcherTimer DT;
DT.Tick += new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
DT.Interval = new TimeSpan(0, 0, 0, 1);
DT.Start();
//DT.Tick -= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
}
}

private async void move_failure_by_flag(string failure_name, int tick_flag) //用async是因为函数里要用到await.Task.Delay()
{
if(...)//飞机达到5000英尺
{
move_to_current_failure(failure_name);//设置其引擎失火
DT.Stop();
}
}

如果我这样写的话,只有第一次执行if (ftc.ShowDialog() == true)的时候正确,如果有第二次,则会继续添加事件DT.Tick += new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));导致其执行多次,我尝试在DT.Start();后面加上DT.Tick -= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));可是没起到作用,请问我应该怎样解决这个问题?
...全文
376 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
正怒月神 2018-01-05
  • 打赏
  • 举报
回复
前面开会去了。刚才回复的不小心删了。。。 这个测试没问题
static System.Timers.Timer timer1 = new System.Timers.Timer(2000);
        static DateTime dt = DateTime.Now.AddSeconds(7);
        static void Main(string[] args)
        {

            timer1.Enabled = true;
            timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
            timer1.Start();

            Console.ReadLine();
        }

        private static void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine("11");
            if(dt<=DateTime.Now)
                timer1.Elapsed -= new ElapsedEventHandler(timer1_Elapsed);
        }  
xuzuning 2018-01-05
  • 打赏
  • 举报
回复
指定 DT.IsEnabled 不好吗?何必绑来绑去
xuzuning 2018-01-05
  • 打赏
  • 举报
回复
其实都 DT.Stop(); 了,事件根本就不会再发生
  • 打赏
  • 举报
回复
这里要点就是先要声明
ElapsedEventHandler proc = null;
然后才为 proc 赋值。
  • 打赏
  • 举报
回复
匿名委托,不过就是把参数封装一下而已。所以假设你不写成匿名委托形式,可以自己明确地封装,例如:
using System;

namespace ConsoleApp1
{
    class Program
    {
        static System.Timers.Timer tmr;

        static void Main(string[] args)
        {
            tmr = new System.Timers.Timer();
            var h = new MyHandler(0, tmr);
            tmr.Start();
            Console.WriteLine("................按任意键结束");
            Console.ReadKey();
        }
    }

    class MyHandler
    {
        public int i;
        System.Timers.Timer tmr;

        public MyHandler(int i, System.Timers.Timer tmr)
        {
            this.tmr = tmr;
            tmr.Elapsed += Tmr_Elapsed;
            tmr.Interval = 1000;
        }

        private void Tmr_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            ++i;
            Console.WriteLine(i);
            if (i == 5)
                tmr.Elapsed -= Tmr_Elapsed;
        }
    }
}

你觉得比较“乱”的外部变量,自己封装到一个 class 中,更加清晰,但是代码多了一些。 所以我还是比较喜爱匿名委托的语法。
  • 打赏
  • 举报
回复
给你写一个控制台的例子
using System;

namespace ConsoleApp1
{
    class Program
    {
       static System.Timers.Timer tmr;

        static void Main(string[] args)
        {
            int i = 0;
            tmr = new System.Timers.Timer();
            System.Timers.ElapsedEventHandler proc = null;
            proc=new System.Timers.ElapsedEventHandler((obj, e) =>
            {
                ++i;
                    Console.WriteLine(i);
                if (i == 5)
                    tmr.Elapsed -= proc;
            });
            tmr.Elapsed += proc;
            tmr.Interval = 1000;
            tmr.Start();
            Console.WriteLine("................按任意键结束");
            Console.ReadKey();
        }
    }
}

Anonymous477 2018-01-05
  • 打赏
  • 举报
回复
引用 12 楼 weixin_37698796 的回复:
[quote=引用 10 楼 StratosBlue 的回复:]
看样子你可能用了局部变量。。
定义一个全局EventHandler对象将其保存起来;

EventHandler _handler = null;

订阅事件之前初始化EventHandler对象

_handler= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
DT.Tick +=_handler;

停止时取消订阅;

DT.Tick -=_handler;

我感觉你说的有道理,但是我运行了以后发现好奇怪啊,这样写的话事件连触发都不触发了。[/quote]

仔细检查一下代码?
weixin_37698796 2018-01-05
  • 打赏
  • 举报
回复
引用 11 楼 qq_38588710 的回复:
注册前先注销
DT.Tick -= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
DT.Tick += new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
这个我试过,看上去取消订阅没有发挥作用,事件还是会累加。
weixin_37698796 2018-01-05
  • 打赏
  • 举报
回复
引用 10 楼 StratosBlue 的回复:
看样子你可能用了局部变量。。 定义一个全局EventHandler对象将其保存起来;

EventHandler _handler = null;
订阅事件之前初始化EventHandler对象

 _handler= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
DT.Tick +=_handler;
停止时取消订阅;

DT.Tick -=_handler;
我感觉你说的有道理,但是我运行了以后发现好奇怪啊,这样写的话事件连触发都不触发了。
易2017 2018-01-05
  • 打赏
  • 举报
回复
注册前先注销
DT.Tick -= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
DT.Tick += new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
Anonymous477 2018-01-05
  • 打赏
  • 举报
回复
看样子你可能用了局部变量。。 定义一个全局EventHandler对象将其保存起来;

EventHandler _handler = null;
订阅事件之前初始化EventHandler对象

 _handler= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
DT.Tick +=_handler;
停止时取消订阅;

DT.Tick -=_handler;
weixin_37698796 2018-01-05
  • 打赏
  • 举报
回复
引用 8 楼 StratosBlue 的回复:
你添加和移除的EventHandler不是同一个对象;
怎样才能让它是同一个对象呢?
Anonymous477 2018-01-05
  • 打赏
  • 举报
回复
你添加和移除的EventHandler不是同一个对象;
weixin_37698796 2018-01-05
  • 打赏
  • 举报
回复
引用 4 楼 gaaa1113 的回复:
关闭之前增加注释事件试试 DT.Tick -= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag)); DT.Stop();
也不行。不知为什么,似乎无法取消订阅
weixin_37698796 2018-01-05
  • 打赏
  • 举报
回复
引用 3 楼 wddw1986 的回复:
DT.Tick -= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
你自己都有取消订阅的代码,想问什么?
我加了这句可是不起作用。
开水加面包 2018-01-05
  • 打赏
  • 举报
回复
关闭之前增加注释事件试试 DT.Tick -= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag)); DT.Stop();
cheng2005 2018-01-05
  • 打赏
  • 举报
回复
DT.Tick -= new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
你自己都有取消订阅的代码,想问什么?
weixin_37698796 2018-01-05
  • 打赏
  • 举报
回复
引用 1 楼 gaaa1113 的回复:
不太明白你的想法
我不清楚
DT.Tick += new EventHandler((sender, e)=>move_failure_by_flag(failure_name, flag));
如何取消订阅? 请问具体是哪个地方我没有说清楚?
开水加面包 2018-01-05
  • 打赏
  • 举报
回复
不太明白你的想法

110,567

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧