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

C# 如何使用System.Timers.Timer访问/修改另一个线程上的控件?,c#,multithreading,user-interface,timer,controls,C#,Multithreading,User Interface,Timer,Controls,因此,我对计时器和线程是新手,我不知道如何制作一个计时器来调用在我的主窗口上编辑/修改控件的函数 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

因此,我对计时器和线程是新手,我不知道如何制作一个计时器来调用在我的主窗口上编辑/修改控件的函数

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>
我得到的错误是: “调用线程无法访问此对象,因为其他线程拥有它。”
另外,我不能很好地处理委托,因此如果您认为在这种情况下有人可以帮助我,那么请发布一个代码示例。

只有与某个控件关联的线程才允许修改该控件

要从其他线程修改控件,您需要将更新代码包装在
委托中
,并将其传递给
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;
        }
    }
}
只需添加:

aTimer.SynchronizingObject = this;
创建计时器后,或使用工具箱->组件中的其他类型的计时器,即System.Windows.Forms.timer


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

问题是您试图从其他线程更新UI线程。在WinForms中,您必须将调用封送回UI线程

按照中的示例,在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 ";
    }

类似于:当存在System.Windows.Forms.timer时,为什么要使用这个线程计时器类来访问可视控件?@davisoa:Bleah,我非常讨厌那些使用递归更新方法的代码段。我总是要花5分钟才能明白发生了什么。@Tudor:但一旦你明白了,就意味着你不必再担心从正确的线程调用这个方法了。调用代码变得更清晰,复杂性也得到了控制。由于我仍然是c#和.NET的高手,我不得不接受你的答案,因为它是最简单的答案,aTimer.SyncronizingObject=this;不起作用:[(关于演员阵容的语法不正确)但是System.Windows.Forms中的计时器工作得很好:[谢谢!感谢您提供的有用信息,但我仍然不愿使用委托,因此我将使用System.Windows.Forms中的计时器,但再次感谢您,我将确保下次记住这一点。updateDelegate必须定义为:
private**delegate**void updateDelegate(字符串文本)感谢您快速而有用的回复!:]它看起来很像System.Windows.Forms.Timer,但我对线程知之甚少,所以目前对我来说,它们几乎是一样的:/天啊,有很多东西要学,没问题。注意,Windows计时器是针对WinForms而不是Wpf的。这不会阻止你使用它。线程是一个很重要的话题,只有当你对C#感到满意时才值得去解决。您的UI只有一个线程,因此您希望保持对用户的响应。如果感兴趣,请参阅以获取解释
    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 ";
    }