2012-10-05 35 views
1

我在谷歌搜索了,让我来显示一个标签在特定时间的方法等几个问题,我发现这一点:C#:哪些允许显示标签在特定时间

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)

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

+0

Yay复制从互联网上粘贴代码。不要将标签文本设置为空,而应将其从表单中删除。否则,最终会在表单上留下大量空的标签,从而堵塞其性能。 – MrFox

+2

@MrFox并非总是如此。首先你假设你正在动态添加标签。也许只有一个状态标签被设置,然后清除并重新设置。这不会导致很多标签。 – Servy

+0

同意,从上下文看起来更像是标签标题改变而不是添加新标签,但我们没有完整的源代码,所以我们可能永远不会知道:) – Charleh

回答

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事件分配一个匿名方法。第一位(发送者,参数)描述方法的参数,然后=>表示“这里是方法”,后面是一段代码(括号内的所有东西)。

+0

DID是什么意思 –

+1

在常规的WinForms应用程序中,您将有一个运行Main函数的线程。如果你看看这个函数,它会调用Run(new Form1())或类似的东西。这就是创建表单的位置,而执行它的线程就是拥有该表单的线程。任何想要改变窗体的东西(或者大部分它的控件 - 因为它们通常是在创建窗体时创建的)应该确保在该线程上这样做。 –

+0

感谢您的解释..我看到DID是某个术语的缩写词是什么意思? –

2

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

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

此代码创建一个anonymous method,然后将其称为上timerElapsed事件。实际上,这会在6秒后清除标签(计时器的建筑间隔)并处理对象,以便仅匿名方法被调用一次。

3

很多问题!

InvokeRequired是由于应用程序的多线程性质。一个基于UI的应用程序有一个UI线程,用户界面的所有更新完成。从非UI线程更新控件的成员将引发交叉线程异常,使用Invoke会将更新编组到UI线程 - 这是合法的。

Action<string>是一个方法的委托,它将调用InfoLabel方法,当使用传入的参数调用委托时 - 例如, action.Invoke( “someString”)。 =>是一个lambda表达式,用于创建一个匿名方法(例如一个没有名字的方法),它将被运行而不是指向一个已命名的方法

+0

我喜欢Sergeys解释更好哈哈:D – Charleh

+0

谢谢,但你的值得+1以及恕我直言:) –

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的新匿名方法的方法。

你也可以使用Task s到解决这个问题,而不是使用定时器:

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()); 
} 
+1

我认为他的意思是让标签在给定的时间后不可见,而不是从那时起显示文本。 – MrFox

+0

@MFFOX你可以使用这种方法。只需在调用此标签之前将标签文本设置为所需内容,然后将空字符串传递给此方法即可。这涵盖了一般情况。 – Servy

+0

提及形式定时器+1 - 虽然我不信任它:D – Charleh