2012-03-01 4 views
2

У меня есть простая страница с кнопкой и надписью на ней. Когда я нажимаю кнопку, я хочу, чтобы текст ярлыка обновлялся, я скопировал код с hereUpdateLayout на WPF нажмите

Однако, когда я использую следующий пример. Текст не обновляется до завершения функции. Есть идеи. Окно Windows 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

ответ

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

Извинения, что я использовал поток sleep для обозначения вытягивания данных из базы данных. Это может занять от 3 до 30 секунд. –

+0

. Затем доступ к базе данных должен выполняться асинхронно или по отдельному рабочему потоку. – Phil

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 блокировать, пока кадр не проходит через очередь рендер, которая является то, что вы на самом деле хотите.

+0

Странно это работает во второй раз, когда нажата кнопка, но не первая. теперь исследуем –

+0

В моем приложении для скриншотов (которое, вероятно, проще, чем ваше) оно работает сразу с места в карьер. Вы можете попробовать 'label1.InvalidateArrange()'. – ianschol

+0

yep это работает, однако ive обнаружил, что добавив thread.sleep (1000), он работает намного лучше. Однако теперь, когда я пытаюсь использовать код на главной странице моего приложения, он работает очень хорошо. Однако, когда я пытаюсь использовать его в другом окне, он не работает. Настолько потрясающе. Ive лишило код обратно к чему-то действительно простому :(Im все еще ищет разрешение –

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); 

     }); 
    } 

Надеюсь, это поможет.

Update: с асинхронным/ждут

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

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

     label1.Content = "Done"; 
    } 
Смежные вопросы