2012-03-02 38 views
2

所以我是新來的定時器和線程,我找不到如何使一個計時器,調用一個函數,編輯/修改我的MainWindow上的控件。如何使用System.Timers.Timer訪問/修改另一個線程上的控件?

XAML代碼:

<Window x:Class="TimerTest.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Title="MainWindow" Height="350" Width="525"> 
<Grid> 
<TextBox Height="287" HorizontalAlignment="Left" Margin="12,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="479" /> 
</Grid> 
</Window> 

C#代碼:

namespace TimerTest 
{ 
    public partial class MainWindow : Window 
    { 
     //Declaring my aTimer as global 
     public static System.Timers.Timer aTimer; 
     //Function that is called 
     public void OnTimedEvent(object source, ElapsedEventArgs e) 
     { 
      textBox1.Text += "SomeText "; 
     } 
     public MainWindow() 
     { 
      InitializeComponent(); 
      aTimer = new Timer(); 
      aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); 
      aTimer.Interval = 1000; // every 5 seconds 
      aTimer.Enabled = true; 
     } 
    } 
} 

的錯誤,我得到: 「因爲不同的線程擁有它調用線程不能訪問此對象。」 P.S .:另外我對代表不太好,所以如果你認爲在這種情況下可以幫助我,那麼請發佈代碼示例。

+0

類似:http://stackoverflow.com/questions/4115598/controls-and-threads/4115634#4115634 – davisoa 2012-03-02 20:26:25

+0

爲什麼在System.Windows.Forms.Timer時使用此線程計時器類來訪問可視化控件? – 2012-03-02 20:36:16

+0

@davisoa:Bleah,我很討厭那些使用遞歸更新方法的代碼片段。總是需要我花5分鐘來了解發生了什麼。 – Tudor 2012-03-02 20:45:47

回答

9

只需添加:

aTimer.SynchronizingObject = this; 

創建計時器後,或者使用ToolBox-> Components中的其他類型的定時器,即System.Windows.Forms.Timer。

您正在使用的計時器在線程池線程上觸發,而不是一個UI,因此需要與UI線程同步以按您希望的方式工作。

+0

因爲我仍然是一個在C#和.NET的noobie,我將不得不與你的答案,因爲它是最簡單的,aTimer.SyncronizingObject = this;沒有工作:[(關於一個強制類型的語法不正確)但System.Windows.Forms中的Timer像一個魅力一樣工作:]謝謝! – 2012-03-02 22:23:42

4

只有與特定控件關聯的線程才允許修改該控件。

從不同的線程,你需要換你的更新代碼delegate內,並通過它來textBox1.Dispatcher.BeginInvoke修改控件:

namespace TimerTest 
{ 
    public partial class MainWindow : Window 
    { 
     private delegate void updateDelegate(string text); 

     private void updateTextBox(string text) 
     { 
      textBox1.Text += text; 
     } 

     //Declaring my aTimer as global 
     public static System.Timers.Timer aTimer; 
     //Function that is called 
     public void OnTimedEvent(object source, ElapsedEventArgs e) 
     { 
      textBox1.Dispatcher.BeginInvoke(
        new updateDelegate(updateTextBox), "SomeText "); 
     } 
     public MainWindow() 
     { 
      InitializeComponent(); 
      aTimer = new Timer(); 
      aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); 
      aTimer.Interval = 1000; // every 5 seconds 
      aTimer.Enabled = true; 
     } 
    } 
} 
+0

謝謝你的有用信息,但我仍然很害怕使用委託,所以我要與System.Windows.Forms中的計時器,但再次感謝你,我會確保下次記住這一點。 – 2012-03-02 22:25:48

+0

updateDelegate必須定義爲:'private ** delegate ** void updateDelegate(string text);' – matuuar 2015-04-08 15:05:22

+0

@matuuar:謝謝。 – Tudor 2015-04-08 15:31:32

1

問題是,您正嘗試從其他線程更新UI線程。在WinForms中,您必須將回調編組回到UI線程。

繼從WPF .NET Best way to trigger an event every minute的例子,在WPF可以使用調度定時器:

public static System.Windows.Threading.DispatcherTimer aTimer; 


    public WindowUpdatedByTimer() 
    { 
     InitializeComponent(); 

     aTimer = new System.Windows.Threading.DispatcherTimer(); 
     aTimer.Tick += new EventHandler(OnTimedEvent); 
     aTimer.Interval = TimeSpan.FromSeconds(5); 
     aTimer.Start(); 

    } 

    public void OnTimedEvent(object source, EventArgs e) 
    { 
     textBox1.Text += "SomeText "; 
    } 
+0

謝謝你的快速和有用的回覆! :]它看起來很像System.Windows.Forms.Timer,但我對線程知之甚少,所以對於我來說,它們大致相同:/天有很多東西要學習xD – 2012-03-02 22:32:20

+0

沒問題。注意Windows定時器是針對WinForms而不是Wpf。這並不會阻止你使用它。一般來說,一旦你對C#感到滿意,線程化就是一個值得探討的重大課題。你的用戶界面有一個線程,所以你想保持對用戶的響應。如果感興趣,請參閱http://msdn.microsoft.com/en-us/library/ms173178.aspx – kaj 2012-03-03 07:58:29

相關問題