Question

Thank you for your time. I have a such a problem with WPF... it updates UI, it updates it only when the method (triggered by the button click) reaches its end. However, in my real app I need to update UI immediately to see info.

I tried to read tutorials and posts and I am ready to give up.... I would appreciate any ideas why it happens and what to do :-).

I have a standard xaml: with a Textbox and a button:

<TextBox Text="{Binding FirstName}"/>
<Button Content="Run" Click="Button_Click" />

Behind it

 public partial class MainWindow
    {
        public Person Person = new Person();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = Person;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Person.FirstName = "John";
            Thread.Sleep(10000);
///// Only Here I can see the update.
        }
    }

And DataContext is:

    public class Person:INotifyPropertyChanged
    {
       private string _FirstName;

        public string FirstName
        {
            get { return _FirstName; }
            set
            {
                if (_FirstName == value)
                    return;
                _FirstName = value;
                OnPropertyChanged("FirstName");

            }
        }
....

Standard OnProertyChanged implementation.

Was it helpful?

Solution

You should never block the UI thread using Sleep. Instead, you may want to put that part of the code on a background thread. Eg, using Task.Factory.StartNew:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Person.FirstName = "John";
    Task.Factory.StartNew( () => {
        Thread.Sleep(10000);

        // ...
    });
}

Note that you can't make any other UI changes inside that thread. If you need to, send them back to the UI thread using Dispatcher.BeginInvoke.

For example, as per the comment:

Person.FirstName = "John";
Task.Factory.StartNew( () => {
    foreach (string mlsNumber in ourMlses) 
    { 
        Listing listing = sourceSite.ParseByMls(mlsNumber); 
        if (listing != null) 
        { 
            var successDb = sourceSite.UpdateListing(listing); 
            if (!successDb) 
            { 
                throw new Exception("Db error"); 
            } 

            Dispatcher.BeginInvoke( () => {

                // UI update that listing have been added to the DB 
            });
        }
    }
} );

OTHER TIPS

I assume you're running a lengthy operation in Button_Click method and want to update UI first with a new FirstName. Try to wrap up your FirstName initialization in Dispatcher.Invoke method:

 private void Button_Click(object sender, RoutedEventArgs e)
 {
      Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, 
            new Action(() => {
                Person.FirstName = "John";
            }));
      // Run a lengthy operation here
 }

It will trigger UI update on PropertyChanged event in the same manner as it was after exiting the Button_Click method.

P.S. However, all code you see here is quite bad practice and I would murder a developer who wrote it. But it may suit some academic purposes. To make a proper solution, it's better to use Commands and handle it in ViewModel instead of click handlers.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top