2012-03-01 35 views
2

我有一个简单的页面,上面有一个按钮和一个标签。当我点击按钮我想要标签文本更新时,我已经复制代码hereWPF上的UpdateLayout点击

但是,当我使用下面的示例。直到功能完成后文本才会更新。有任何想法吗。 WPF窗体窗体使用按钮和标签放在上面。

我在按钮的代码隐藏下面有以下内容,第一条消息从不显示。

Thread.Sleep意味着从数据库中提取数据返回到屏幕,这可能需要3到30秒的时间,因此为什么我想让它显示用户的东西。

任何想法???

using System.Threading; 
using System.Windows; 
using System.Windows.Threading; 

namespace NetSpot.RESV4.Presentation 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, RoutedEventArgs e) 
     { 
      label1.Content = "Button 1 Clicked"; 
      ForceUIToUpdate(); 
      Thread.Sleep(4000); 
      label1.Content = "button 1 Updated"; 
     } 

     public static void ForceUIToUpdate() 
     { 
      DispatcherFrame frame = new DispatcherFrame(); 
      Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Render, new  DespatcherOperationCallback(delegate(object parameter) 
     { 
      frame.Continue = false; 
      return null; 
     }), null); 
     Dispatcher.PushFrame(frame); 
    } 

    } 
} 
+0

是否有特别的理由不使用绑定属性,INotifyPropertyChanged的?如果不是,那看起来不如调度员复杂。 – ianschol 2012-03-01 15:54:23

回答

3

如果您希望标签在4秒后更新,您最好使用分派器定时器。

public partial class Window1 : Window 
{ 
    readonly DispatcherTimer m_timer = new DispatcherTimer(); 
    public Window1() 
    { 
     InitializeComponent(); 

     m_timer.Interval = TimeSpan.FromSeconds(4); 
     m_timer.Tick += TimerOnTick; 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     label1.Content = "Button 1 Clicked"; 
     m_timer.Start(); 
    } 

    private void TimerOnTick(object sender, EventArgs eventArgs) 
    { 
     m_timer.Stop(); 
     label1.Content1 = ... 
    } 
+0

道歉我正在使用线程睡眠来表示从数据库中提取数据。这可能需要3到30秒的时间 – 2012-03-01 17:07:23

+0

然后,访问数据库应该异步完成,或者在单独的工作线程上完成。 – Phil 2012-03-01 17:34:30

1

直接回答你的问题(无论方法论的),你永远信号,它应该初始值变化后更新UI。该信号在点击事件结束后自动发生。呼叫添加到label1.UpdateLayout(),像这样:

private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     label1.Content = "Button 1 Clicked"; 
     label1.UpdateLayout(); 
     ForceUIToUpdate(); 
     Thread.Sleep(4000); 
     label1.Content = "button 1 Updated"; 
    } 

现在你应该看到预期的行为。

编辑 - 给这个版本的ForceUIToUpdate一个尝试。

public static void ForceUIToUpdate() 
    { 
     DispatcherFrame frame = new DispatcherFrame(); 
     Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Render, new  DispatcherOperationCallback(delegate(object parameter) 
     { 
      frame.Continue = false; 
      return null; 
     }), null); 
     Dispatcher.PushFrame(frame); 
    } 

这应该会导致ForceUIToUpdate阻塞,直到帧通过Render队列,这正是您实际需要的。

+0

strangly这是第二次按钮被点击,但不是第一次。现在调查 – 2012-03-01 17:41:51

+0

在我的临时应用程序(可能比你更简单)中,它可以正常工作。你可以试试'label1.InvalidateArrange()'。 – ianschol 2012-03-01 21:31:15

+0

是的它的工作原理,但是我发现通过添加一个thread.sleep(1000)它效果更好。但是现在,当我尝试在我的应用程序的主页上使用代码时,它的功能非常好。但是,当我尝试在另一个窗口它不工作。如此疯狂。我已经将代码剥离回了一些非常简单的东西:(我仍然在寻找分辨率 – 2012-03-02 11:31:16

0

尽量不要让当前线程进入睡眠状态,而是简单地通过调度程序设置另一个线程的值。

private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     Task.Run(() => 
     { 
      Dispatcher.Invoke(new Action(() => 
      { 
       label1.Content = "Waiting"; 
      }), null); 

      Thread.Sleep(2000); 

      Dispatcher.Invoke(new Action(() => 
      { 
       label1.Content = "Done"; 
      }), null); 

     }); 
    } 

希望这会有所帮助。

更新:与异步/等待

private async void button1_Click(object sender, RoutedEventArgs e) 
    { 
     label1.Content = "Waiting"; 

     await Task.Run(() => Thread.Sleep(2000)); 

     label1.Content = "Done"; 
    }