1

After some search on web I have set up this simple example:

PropertyChangedBase.cs

public class PropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName) {
        //Raise the PropertyChanged event on the UI Thread, with the relevant propertyName parameter:
        Application.Current.Dispatcher.BeginInvoke((Action)(() => {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }));
    }
 }

UserViewModel.cs

public class UserViewModel : PropertyChangedBase
{
    private Visibility _showUserWindow = Visibility.Collapsed;
    public Visibility ShowUserWindow {
        get { return _showUserWindow; }
        set {
            _showUserWindow = value;
            OnPropertyChanged("ShowUserWindow"); //This is important!!!
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid Margin="43,28,247,129" Background="AliceBlue" Visibility="{Binding ShowUserWindow}"/>
        <Button Content="Button" HorizontalAlignment="Left" Margin="349,150,0,0" VerticalAlignment="Top" Width="75" PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown"/>
    </Grid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    UserViewModel userViewModel;

    public MainWindow() {
        InitializeComponent();

        userViewModel = new UserViewModel();
        DataContext = userViewModel;
    }

    private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
        userViewModel.ShowUserWindow = Visibility.Visible;
        Thread.Sleep(1000);
        userViewModel.ShowUserWindow = Visibility.Collapsed;
    }
}

Right now grid becomes collapsed after 1 sec, I would like to update UI before timer starts. What I am doing wrong?

Edit: Thread.Sleep line immitates some work, that takes some time to complete. Grid should become visible before work starts and show some info about that work and become collapsed after work is done.

Gytis S
  • 159
  • 1
  • 8

2 Answers2

2

Well, you should consider doing the Thread.Sleep(1000) operation on a separate thread, not on the UI thread. Check this for that. Other than that, try to use yourGrid.UpdateLayout() method after setting its visibility to collapsed.

LE: Most probably, his Thread.Sleep(1000) stands for something like a database operation, for example, something that takes time.

LE2: A BackgroundWorker will do the trick. Check this link!

Community
  • 1
  • 1
RazvanR
  • 412
  • 5
  • 14
  • I'm thinking the BackgroundWorker helped you (right?), just to make it clear for the future visitors. Good luck !;) – RazvanR Mar 17 '15 at 12:53
  • `UpdateLayout()` will not help. I don't know the exact reason of it, but I think that any UI redraw operations is send to Dispatcher queue, and the queue will not continue until the current code in UI thread is finished (and it obviously will not finish until `Thread.Sleep` is finished). – Aleksey Shubin Mar 17 '15 at 12:53
1

If you are using .NET 4.5, you can use Task.Delay() to allow UI to update itself before starting the actual work:

private async void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
    userViewModel.ShowUserWindow = Visibility.Visible;
    await Task.Delay(1);
    Thread.Sleep(1000);
    userViewModel.ShowUserWindow = Visibility.Collapsed;
}

Please note that await Task.Delay(1); should be used even after you replace Thread.Sleep(1000) with actual work.

However this should be used only if your work can be done only in UI thread and cannot be moved to a background thread (for example, massive loading of UI elements). Otherwise the correct approach is to move the work to a background thread:

private async void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
    userViewModel.ShowUserWindow = Visibility.Visible;
    await Task.Start(() => {
        Thread.Sleep(1000);
    };
    userViewModel.ShowUserWindow = Visibility.Collapsed;
}
Aleksey Shubin
  • 1,960
  • 2
  • 20
  • 39