【问题标题】:How to update a control on WPF MainWindow如何更新 WPF MainWindow 上的控件
【发布时间】:2013-08-16 13:59:52
【问题描述】:

如何在下面的代码中更新我的 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;
        } 
    }
}

【问题讨论】:

标签: c# wpf multithreading


【解决方案1】:

你可以试试这样的:

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

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

阅读更多关于Dispatcher.BeginInvoke Method here

【讨论】:

    【解决方案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,然后在知道更新已完成的情况下继续当前线程。

    这是一个带有完整示例的similar question

    【讨论】:

    • 如果你只有一个 UI 线程,你也可以使用Application.Current 而不是保存Dispatcher.CurrentDispatcher,正如@JMK 指出的那样。
    【解决方案3】:

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

    首先,您可以使用DispatcherTimer 类而不是this MSDN article 中演示的Timer 类,它会修改调度程序线程上Elapsed 事件中的UI 元素。

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

    label1.Dispatcher.BeginInvoke(
          System.Windows.Threading.DispatcherPriority.Normal,
          new Action(
            delegate()
            {
              label1.Content = s;
            }
        ));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-04
      • 2016-01-25
      • 1970-01-01
      • 2019-06-09
      • 2017-03-07
      • 1970-01-01
      相关资源
      最近更新 更多