部分代码没有延迟执行

时间:2016-07-22 14:15:31

标签: c#

我的应用检测是否已更改。如果ip与之前的不同,则会将新的ip保存到文件中。看起来很简单。

延迟功能:

public void MyDelay(int milliseconds)
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    while (stopwatch.ElapsedMilliseconds <= (long)milliseconds)
    {
        Application.DoEvents();
    }
}

按钮点击事件:

private void button1_Click(object sender, EventArgs e)
  {
    pictureBox1.BackColor = Color.Green;

    while (true)
    {
        while (true)    //force obtain new_ip
        {

            try

            {
                new_ip = new System.Net.WebClient().DownloadString("https://api.ipify.org");

            }

            catch
            {
                MyDelay(1000);
                continue;

            }
            break;


        }


        if (old_ip != new_ip)
        {
            pictureBox1.BackColor = Color.Red;
            File.AppendAllText(@"C:\users\pc\Desktop\ip.txt", new_ip + "\r\n");
            old_ip = new_ip;
            MessageBox.Show("New ip saved");
        }
        pictureBox1.BackColor = Color.Green;

    }
 }

问题是,如果我将代码留下这样的部分:pictureBox1.BackColor = Color.Green;将不会执行。

我必须改变这一点:

pictureBox1.BackColor = Color.Green;

对此:

pictureBox1.BackColor = Color.Green;
MyDelay(1);

现在图片框的颜色正在发生变化。为什么延迟修复呢?如果我把MessageBox放在Picturebox中,问题就不存在了。它也可以作为没有MyDelay的魅力。那有什么意义呢?

另一个问题:它应该每1秒检查一次ip。那么为什么当我改变ip时我必须等待大约5秒才能进行变化检测?它应该在连接出现后1秒后保存新的ip,但识别更改需要大约5秒

4 个答案:

答案 0 :(得分:1)

您正在主线程中完成所有工作。 UI也在主线程中更新。这意味着您不允许UI以任何方式更新自身。

当您调用延迟函数时,它会调用Application.DoEvents(),让UI自行更新。

您应该重构代码以使用计时器,异步方法或后台工作线程,以便UI可以保持响应。

答案 1 :(得分:1)

你不应该在按钮点击中创建一个无限的while (true),它会阻止gui进行更新。这就是为什么你的PictureBox没有重新绘制(但代码被执行)的原因。如果您将睡眠放在(包含Application.DoEvents(),则会处理绘制消息并重新绘制PictureBox。但是仍然阻止了GUI线程。

以这种方式使用Application.DoEvents()不良做法,因为此处还处理了其他按钮/ formcloses,这会使您的应用程序非常不稳定。 所以摆脱Application.DoEvents()..

使用Timer来检查外部IP的网站!

类似于: PSEUDO

public class Form1: Form
{
    private Timer _timer;

    public Form1()
    {
        InitializeComponent();
        _timer = new Timer(.....);
        _timer.Tick += Timer_Tick;
        // etc!!!
    }

}

private void Timer_Tick(object sender, EventArgs e)
{
    string new_ip;
    try
    {
        new_ip = new System.Net.WebClient().DownloadString("https://api.ipify.org");

    }
    catch 
    { 
        return;
    }

    if (old_ip != new_ip)
    {
        pictureBox1.BackColor = Color.Red;
        File.AppendAllText(@"C:\users\pc\Desktop\ip.txt", new_ip + "\r\n");
        old_ip = new_ip;
        MessageBox.Show("New ip saved");
    }
    else
        pictureBox1.BackColor = Color.Green;
}

答案 2 :(得分:0)

在剪切的.net内部无法更新界面,您可以使用Application.DoEvents()来解决问题。也许this question会有所帮助。

答案 3 :(得分:0)

如果我理解你的意图,你可以尝试异步等待(不知道为什么它需要一个while循环并尝试catch来获取url的结果):

    private async void button1_Click(object sender, EventArgs e)
    {
        pictureBox1.BackColor = Color.Green;

        var newIp = await GetIpAsync();

        if (oldIp != newIp)
            pictureBox1.BackColor = Color.Red;
    }

    private async Task<string> GetIpAsync()
    {
        using (var httpClient = new HttpClient())
        {
            return await httpClient.GetStringAsync(@"https://api.ipify.org");
        }
    }