1

我在 google 中搜索了一种允许我在特定时间显示标签的方法,我发现了这个:

public void InfoLabel(string value)
        {
            if (InvokeRequired)
            {
                this.Invoke(new Action<string>(InfoLabel), new object[] { value });
                return;
            }
            barStaticItem3.Caption = value;

            if (!String.IsNullOrEmpty(value))
            {
                System.Timers.Timer timer = new System.Timers.Timer(6000) { Enabled = true };
                timer.Elapsed += (sender, args) =>
                {
                    this.InfoLabel(string.Empty);
                    timer.Dispose();
                };
            }

        }

我真的无法特别理解这种方法:

- 为什么我们使用:InvokeRequired

-这个方法有什么用:this.Invoke()

-这是为了什么:new Action<string>(InfoLabel)

- 为什么我们使用那个标志:=>

4

4 回答 4

4

所有与调用相关的东西都是因为编写该代码的人使用了错误的代码Timer(语言中有很多)。你应该在System.Windows.Forms.Timer这里使用。

public void InfoLabel(string value)
{
    System.Windows.Forms.Timer timer = new Timer();

    timer.Interval = 1000;//or whatever the time should be.
    timer.Tick += (sender, args) =>
        {
            label1.Text = value;
            timer.Stop();
        };
    timer.Start();
}

表单计时器将在其自己的实现中包含代码,这些代码与您的示例中的代码类似(尽管我发现它是一种特别混乱的方式)。它将确保Tick事件在 UI 线程中运行,因此您无需添加所有样板代码。

=>一个 lambda 表达式。这是一种定义新匿名方法的方法,该方法接受两个参数senderargs.

您也可以使用Tasks 来解决这个问题,而不是使用计时器:

public void InfoLabel2(string value)
{
    Task.Factory.StartNew(() => Thread.Sleep(1000)) //could use Task.Delay if you have 4.5
        .ContinueWith(task => label1.Text = value
            , CancellationToken.None
            , TaskContinuationOptions.None
            , TaskScheduler.FromCurrentSynchronizationContext());
}
于 2012-10-05T15:22:17.527 回答
3

Many questions!

InvokeRequired is due to the multi-threaded nature of applications. A UI based application has a UI thread on which all the updates for the user interface are done. Updating a member of the control from a non-UI thread will throw a cross thread exception, using Invoke will marshal the update to the UI thread - which is legal.

The Action<string> is a delegate for a method, it will call the InfoLabel method when the delegate is called with the passed in arguments - e.g. action.Invoke("someString"). The => is a lambda expression which is used to create an anonymous method (e.g. a method with no name) which will be run instead of pointing to a named method

于 2012-10-05T15:20:44.717 回答
3

InvokeRequired检查代码当前是否在创建表单的线程上运行。如果不是,则该函数需要在 DID 创建表单的线程上调用自身,因为 WinForms 代码不是线程安全的。

Action 是一个委托类型,它描述了一个接受字符串的函数(参见 InfoLabel 函数?这就是它所指的)。

 this.Invoke(new Action<string>(InfoLabel), new object[] { value });

上面说的。请从函数 InfoLabel 创建一个 Action 类型的新委托,并使用创建它的线程调用它。当您调用它时,将对象“值”传递给它。即在创建表单的线程上调用 InfoLabel(value)。请注意,它之后直接从函数返回,因此函数的“肉”都没有在错误的线程上运行(此时我们在错误的线程上,否则 InvokeRequired 不会为真)。当 Invoke 再次运行该函数时,它将在正确的线程上,并且 InvokeRequired 将为 false,因此这段代码将不会运行。

timer.Elapsed += (sender, args) =>
                {
                    this.InfoLabel(string.Empty);
                    timer.Dispose();
                };

上面的代码为定时器的 Elapsed 事件分配了一个匿名方法。第一个位 (sender, args) 是描述方法的参数,然后=>是说“方法来了”,然后是一段代码(括号内的所有内容)。

于 2012-10-05T15:24:25.427 回答
2

InvokeRequired用于检查我们是否从控制持续存在InfoLabel的 UI 线程中调用该方法。barStaticItem3如果线程不同(InvokeRequired),则this.Invoke(new Action<string>(InfoLabel), new object[] { value });调用相同的方法 - 这会从 UI 线程中调用相同的方法。

timer.Elapsed += (sender, args) =>
            {
                this.InfoLabel(string.Empty);
                timer.Dispose();
            };

此代码创建一个匿名方法timer,然后在'sElapsed事件上调用该方法。实际上,这会在 6 秒(构造时的计时器间隔)后清除标签并处理timer对象,以便仅调用一次此匿名方法。

于 2012-10-05T15:16:33.753 回答