如何使用System.Timers.Timer访问/修改另一个线程上的控件?

时间:2012-03-02 20:24:16

标签: c# multithreading user-interface timer controls

所以我是计时器和线程的新手,我无法找到如何制作一个调用编辑/修改MainWindow控件的函数的计时器。

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。:另外我对代表不太好,所以如果你认为在这种情况下可以帮助我,那么请发一个代码样本。

3 个答案:

答案 0 :(得分:13)

只需添加:

aTimer.SynchronizingObject = this;

创建计时器后,或使用ToolBox-&gt;组件中的OTHER类型的计时器,即System.Windows.Forms.Timer。

您正在使用的计时器触发线程池线程而不是UI线程,因此需要与UI线程同步以按您希望的方式工作。

答案 1 :(得分: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;
        }
    }
}

答案 2 :(得分:1)

问题是您正在尝试从其他线程更新UI线程。在WinForms中,您必须将回调编组回UI线程。

按照WPF .NET Best way to trigger an event every minute中的示例,在WPF中,您可以使用Dispatcher Timer:

    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 ";
    }