4

如何在下面的代码中更新我的 label1 文本?我收到“调用线程无法访问此对象,因为另一个线程拥有它”错误。我读过其他人使用过 Dispatcher.BeginInvoke 但我不知道如何在我的代码中实现它。

public partial class MainWindow : Window
{
    System.Timers.Timer timer;

    [DllImport("user32.dll")]        
    public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);

    public struct tagLASTINPUTINFO
    {
        public uint cbSize;
        public Int32 dwTime;
    }

    public MainWindow()
    {
        InitializeComponent();
        StartTimer();
        //webb1.Navigate("http://yahoo.com");
    }

    private void StartTimer()
    {
        timer = new System.Timers.Timer();
        timer.Interval = 100;
        timer.Elapsed += timer_Elapsed;
        timer.Start();
    }

    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
        Int32 IdleTime;
        LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
        LastInput.dwTime = 0;

        if (GetLastInputInfo(ref LastInput))
        {
            IdleTime = System.Environment.TickCount - LastInput.dwTime;
            string s = IdleTime.ToString();
            label1.Content = s;
        } 
    }
}
4

3 回答 3

6

你可以尝试这样的事情:

if (GetLastInputInfo(ref LastInput))
{
    IdleTime = System.Environment.TickCount - LastInput.dwTime;
    string s = IdleTime.ToString();

    Dispatcher.BeginInvoke(new Action(() =>
    {
        label1.Content = s;
    }));
}

在此处阅读有关Dispatcher.BeginInvoke 方法的更多信息

于 2013-08-16T14:04:51.200 回答
2

您需要Dispatcher.CurrentDispatcher从主线程中保存:

public partial class MainWindow : Window
{
    //...
    public static Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
    //...
}

然后,每当您需要在主线程的上下文中执行某些操作时,您都可以:

MainWindow.dispatcher.Invoke(() => {
   label1.Content = s;
});

注意,Dispatcher.BeginInvoke它是异步的,不像Dispatcher.Invoke. 您可能需要在这里进行同步调用。对于这种情况,异步调用似乎没问题,但通常您可能希望更新主线程上的 UI,然后在知道更新已完成的情况下继续当前线程。

这是一个带有完整示例的类似问题。

于 2013-08-16T14:18:51.317 回答
1

有2种方法可以解决这个问题:

首先,您可以使用一个DispatcherTimer类来代替此 MSDN 文章Timer中演示的类,它会修改Dispatcher 线程上的事件中的UI 元素。Elapsed

其次,对于您现有的Timer类,您可以Dispatcher.BegineInvoke()在 timer_Elapsed 事件中使用以下代码中的方法:

label1.Dispatcher.BeginInvoke(
      System.Windows.Threading.DispatcherPriority.Normal,
      new Action(
        delegate()
        {
          label1.Content = s;
        }
    ));
于 2013-08-16T14:11:31.540 回答