C# 如何使用System.Timers.Timer访问/修改另一个线程上的控件?
因此,我对计时器和线程是新手,我不知道如何制作一个计时器来调用在我的主窗口上编辑/修改控件的函数 Xaml代码: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
<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 ";
}