【请教】C#如何使用定时器更新界面

tiger波波 2016-12-27 04:05:51
大家好:
我写了一个程序,根据指定的文件头(4字节),文件尾(4字节),文件长度,从一个二进制数据文件中检索是否存在符合条件的文件。

我想点击【检索】按钮后,程序开始检索,同时界面上的label控件显示“正在检索。。。。。。”,同时设想着启动定时器,“正在检索”后边的。。。不停地增减,显示动态效果。

根据网上找的代码,编辑如下:

int m_iInterval;

public MainForm()
{
InitializeComponent();

m_iInterval = 1;
}

public delegate void TimerFunc();

public void UpdateStatus()
{
switch (m_iInterval)
{
case 1:
m_iInterval += 1;
label_State.Text = "正在检索.";
break;
case 2:
m_iInterval += 1;
label_State.Text = "正在检索..";
break;
case 3:
m_iInterval += 1;
label_State.Text = "正在检索...";
break;
case 4:
m_iInterval += 1;
label_State.Text = "正在检索....";
break;
case 5:
m_iInterval += 1;
label_State.Text = "正在检索.....";
break;
case 6:
m_iInterval = 1;
label_State.Text = "正在检索......";
break;
}
}

public void OnTimer(object source, System.Timers.ElapsedEventArgs e)
{
TimerFunc func = new TimerFunc(UpdateStatus);
this.Invoke(func, new Object[] { });
}

我在【检索】按钮的相应函数里把定时器的enable设为true,结果点击【检索】按钮后,label还是显示“就绪”,等检索完成了,它才变成“正在检索。。。”

请问这是怎么回事?如何实现我说的这个效果?
...全文
1606 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
海阔天空CE 2017-01-05
  • 打赏
  • 举报
回复
不用定时器,BackGroundWorker 非常合适
  • 打赏
  • 举报
回复
引用 17 楼 youyingbo 的回复:
[quote=引用 1 楼 Hello_Ge 的回复:]

        public void UpdateStatus()
        {
            label1.Text = str;
        }
        int i = 1;
        public delegate void TimerFunc();

        private void button2_Click(object sender, EventArgs e)
        {
            timer1.Start();
        }
        string str = "加载中。。。";

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (i == 10)
            {
                str = "加载中。。。";
                i = 1;
            }
            str += "。";
            TimerFunc func = new TimerFunc(UpdateStatus);
            this.Invoke(func, new Object[] { });
            i++;
        }
你好,你的开始执行函数一下就执行完了,所以是可以的,如果启动定时器后,不马上返回而sleep100秒,那动画效果应该100秒后才开始[/quote] 定时器就是为了控件什么时候启动动漫效果,至于什么时候启动你自己控制就好了,我只是给你写了启动动漫的效果
tiger波波 2017-01-05
  • 打赏
  • 举报
回复
看了大家的发言,看来耗时的检索任务(你们可以简单地理解为sleep10秒钟)必须放在线程里去执行,然后在线程里刷新界面。 我这里不需要显示耗时操作的进程,只需要让用户知道它在执行操作就行了,也就是说界面显示2个状态:运行中,已完成。
tiger波波 2017-01-05
  • 打赏
  • 举报
回复
引用 1 楼 Hello_Ge 的回复:

        public void UpdateStatus()
        {
            label1.Text = str;
        }
        int i = 1;
        public delegate void TimerFunc();

        private void button2_Click(object sender, EventArgs e)
        {
            timer1.Start();
        }
        string str = "加载中。。。";

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (i == 10)
            {
                str = "加载中。。。";
                i = 1;
            }
            str += "。";
            TimerFunc func = new TimerFunc(UpdateStatus);
            this.Invoke(func, new Object[] { });
            i++;
        }
你好,你的开始执行函数一下就执行完了,所以是可以的,如果启动定时器后,不马上返回而sleep100秒,那动画效果应该100秒后才开始
Anymore 2017-01-01
  • 打赏
  • 举报
回复
这需求不建议用timer,检索动作中有变化时候去刷新ui即可。
  • 打赏
  • 举报
回复
另外,所强调的“事件驱动设计”的概念,并不是说胡乱使用 c# 的某个关键字。跟编程语言无关,你设计软件流程的方式应该是事件驱动的。 千万不要低俗地仅仅去匹配 c# 的某个关键字。不管你用什么编程关键字,不管你用什么设计和实现机制,重要的是其本质。 重要地是你会不会画流程图。初学者画程序流程图,只会简单的函数,有一个单一的输入、一个单一的输出。根本不会在流程图上标明事件驱动机制。这样就能看他的软件思维方式的局限。
  • 打赏
  • 举报
回复
我强调的是某些人在入门时缺少基本设计知识学习,并不是强调“1毫秒”这个数值还是“100毫秒”这个数值的问题。 比如说通过微信能够收到其它好友发来的信息,是怎么收到的?是微信每隔500毫秒就查询一下数据库?如果你这样设计软件,那么你就落入那些培训初中生学习编程的入门课程中,而你根本就会坑了你雇佣你的老板。 不管是“大的”跨进程通讯,还是“小的”进程内状态改变 Notify 模式,都要知道不能纠结上什么 timer 的外道做法的。有信息就立刻响应,没信息就什么都不干,这才是干净的程序。
  • 打赏
  • 举报
回复
"1毫秒“只是说明某些人的编程思维方式。 就算不是1毫秒,设置为50、250,如果把软件中成百上千的“事件”当作是“定时监控”来看待,这种思维方式就只了解一半技术。
x1983c 2017-01-01
  • 打赏
  • 举报
回复
Timer的间隔是1,这个代表1毫秒,最好设大点比如250。
  • 打赏
  • 举报
回复
实际上,你的所谓的 Timer 是编程的大忌,这里我只是简单提示你真正了解一下它的问题实质。 有些人不会事件驱动设计机制,于是滥用 Timer。 其实任何代码都可能严重消耗CPU,更何况你可能以为1毫秒触发一次定时器是很“高大上”的监控行为,实际上这类代码是“一颗老鼠屎坏了一锅汤”的,会造成程序整体运行严重卡顿,而且不懂的人还你很难找到是谁搞的鬼(?)来严重降低了程序。许多初学者以为.net 程序原本就是很慢的,所以根本不知道这是bug。如果遇到一个不懂开发和测试的项目经理,这种老鼠屎最终就会演变为定时炸弹! 当你要更新界面上的“正在检索123121”的时候,你直接使用 BeginInvoke/Invoke 来更新界面就行了。当底层机制要通知自己的宿主“状态改变了”的时候,它触发自己的事件,让自己的客户程序去捕获事件就行了。 哪里用得着什么 1 毫秒一次的定时器?
  • 打赏
  • 举报
回复
举个例子,你应该是类似这样来写代码
void btn检索_Click(object sender, EventArgs e)
{
    启动Timer......;
    ThreadPool.QueueUserWorkItem(h =>
    {
        执行耗时的检索操作......;
        this.BeginInvoke((Action)delegate
        {
             在控件上显示检索结果提示信息。
        });
    });
}
当 btn检索_Click 已经执行完毕之后(UI 线程回到了底层去刷新界面),才开始耗时的检索操作。因此这是异步的操作。
  • 打赏
  • 举报
回复
那你根本没有贴出你的【检索】的代码,谁知道你是怎么写的啊? 检索功能,如果是 UI 窗口线程调用它的,那么它卡死了 UI 刷新操作。那么你的【检索】操作内部的实际检索功能应该是异步子线程里执行(只有最后检索完毕之后才使用 BeginInvoke/Invoke 语法来在街面上写上检索结果)。 也就是说,你的【检索】方法的代码先执行完毕,然后才开始真正异步地进行检索。这是一个异步处理。
夏天的枫 2016-12-30
  • 打赏
  • 举报
回复
引用 6 楼 hjq624779687 的回复:

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        Timer timer;
        int i;
        private void button_Click(object sender, EventArgs e)
        {
            i = 0;
            this.textBox.Text = "zh";
            timer = new Timer();
            timer.Interval = 50;
            timer.Tick += timer_Tick;
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            
            switch(i)
            {
                case 20:
                    this.textBox.Text = "正在上车";
                    break;
                case 40:
                    this.textBox.Text = "正在关门";
                    break;
                case 80:
                    this.textBox.Text = "正在行驶";
                    break;
                case 100:
                    this.textBox.Text = "我下车了!";
                    timer.Stop();
                    timer.Dispose();
                    break;
            }
            this.progressBar.Value = i;
            i++;
        }
    }
winform,三个控件 button textbox progressbar,自己去玩吧

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        Timer timer;
        int i;
        private void button_Click(object sender, EventArgs e)
        {
            i = 0;
            this.textBox.Text = "停止驾驶";
            this.button.Enabled = false;
            timer = new Timer();
            timer.Interval = 50;
            timer.Tick += timer_Tick;
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            
            switch(i)
            {
                case 20:
                    this.textBox.Text = "正在上车";
                    break;
                case 40:
                    this.textBox.Text = "正在关门";
                    break;
                case 80:
                    this.textBox.Text = "正在行驶";
                    break;
                case 100:
                    this.textBox.Text = "我下车了!";
                    this.button.Enabled = true;
                    timer.Stop();
                    timer.Dispose();
                    break;
            }
            this.progressBar.Value = i;
            i++;
        }
    }
最好设置下button的Enabled属性,防止多次点击
夏天的枫 2016-12-30
  • 打赏
  • 举报
回复

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        Timer timer;
        int i;
        private void button_Click(object sender, EventArgs e)
        {
            i = 0;
            this.textBox.Text = "zh";
            timer = new Timer();
            timer.Interval = 50;
            timer.Tick += timer_Tick;
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            
            switch(i)
            {
                case 20:
                    this.textBox.Text = "正在上车";
                    break;
                case 40:
                    this.textBox.Text = "正在关门";
                    break;
                case 80:
                    this.textBox.Text = "正在行驶";
                    break;
                case 100:
                    this.textBox.Text = "我下车了!";
                    timer.Stop();
                    timer.Dispose();
                    break;
            }
            this.progressBar.Value = i;
            i++;
        }
    }
winform,三个控件 button textbox progressbar,自己去玩吧
泡泡龙 2016-12-30
  • 打赏
  • 举报
回复
不要用timer,要用event,然后再event里面判断一下不要重入
「已注销」 2016-12-29
  • 打赏
  • 举报
回复
在你的 检索任务线程里报告状态时调用 Timer 更新界面。 最好用 BackgroundWorker 这个很适合。
bbjiabcd 2016-12-29
  • 打赏
  • 举报
回复
这委托用的…… 如果不需要显示进度的话,根本不需要频繁地调用this.Invoke(...) 建议把检索操作放在后台线程里面做,显示进度的时候在后台线程中调用this.Invoke(...)或相关方法显示检索进度,检索完毕最后调用一次this.Invoke(...)返回结果。 至于界面上显示动态效果,直接用timer就能搞定。
JimCarter 2016-12-27
  • 打赏
  • 举报
回复
当前线程正在执行任务,来不及刷新你的UI界面,所以: 1.用label.refresh()刷新一下就能及时显示了。(好像是这个方法) 2.用线程,在另一个线程里,去更新你的label,不过要用到label.invoke().
  • 打赏
  • 举报
回复
public void UpdateStatus() { label1.Text = str; } int i = 1; public delegate void TimerFunc(); private void button2_Click(object sender, EventArgs e) { timer1.Start(); } string str = "加载中。。。"; private void timer1_Tick(object sender, EventArgs e) { if (i == 10) { str = "加载中。。。"; i = 1; } str += "。"; TimerFunc func = new TimerFunc(UpdateStatus); this.Invoke(func, new Object[] { }); i++; }
  • 打赏
  • 举报
回复

        public void UpdateStatus()
        {
            label1.Text = str;
        }
        int i = 1;
        public delegate void TimerFunc();

        private void button2_Click(object sender, EventArgs e)
        {
            timer1.Start();
        }
        string str = "加载中。。。";

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (i == 10)
            {
                str = "加载中。。。";
                i = 1;
            }
            str += "。";
            TimerFunc func = new TimerFunc(UpdateStatus);
            this.Invoke(func, new Object[] { });
            i++;
        }

111,094

社区成员

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

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

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