-1

I have a MainWindow.xaml that gets populated with UserControls. I have a control in the MainWindow.xaml that has a button. The button is bound to the following command in MyViewModel.cs:

    public ICommand MyCommand
    {
        get
        {
            return Get(() => MyCommand, () => new RelayCommand(ExecuteMyCommand, CanExecuteMyCommand));
        }
    }

    public void ExecuteMyCommand()
    {
        Messenger.Default.Send(new NotificationMessage(this, MainWindowMessageBus.ShowPopup1), MainWindowMessageBus.Token);
        Method1();
        Messenger.Default.Send(new NotificationMessage(this, MainWindowMessageBus.ShowPopup2), MainWindowMessageBus.Token);
        Method2();
    }

    public bool CanExecuteInsertBedCommand()
    {
        return true;
    }

Method1() and Method2() execute code that take about 5 seconds each. The messengers are sending messages to the codebehind MainWindow.xaml.cs:

    Popup1 popup1;
    Popup2 popup2;

    private void NotificationMessageReceived(NotificationMessage msg)
    {
        switch(msg.Notification)
        {
            case MainWindowMessageBus.ShowPopup1:
                popup1 = new Popup1();
                ControlContainer.Children.Add(popup1);
                break;
            case MainWindowMessageBus.ShowPopup2:
                // Remove popup1
                ControlContainer.Children.Remove(popup1);
                popup1 = null;
                // Add popup2
                popup2 = new Popup2();
                ControlContainer.Children.Add(popup2);
                break;
            default:
                break;
        }
    }

Expected results: upon pressing my button, Popup1 shows immediately and stays in the window while Method1() executes. Then, Popup2 replaces Popup1 in the window and Method2() executes.

Actual results: upon pressing my button, nothing happens in the UI. Method1() and Method2() execute as expected, and after they both run (~10 seconds), Popup2 is displayed. I never see Popup1.

I tried a couple threading/async methods, but they didn't work. How can I get ExecuteMyCommand() to update the UI as it goes?

EDIT

Ok so I can't answer my own question for some reason. I don't think this question is a duplicate of the specified thread, since that would imply that I already knew I needed to run Method1() in the background, which I did not. Anyways, here's what I changed:

public async void ExecuteMyCommand()
        {
            Messenger.Default.Send(new NotificationMessage(this, MainWindowMessageBus.ShowPopup1), MainWindowMessageBus.Token);
            await Task.Run(() =>
            {
                Method1();
            });
            Messenger.Default.Send(new NotificationMessage(this, MainWindowMessageBus.ShowPopup2), MainWindowMessageBus.Token);
            Method2();
        }
  • You're doing work in the UI thread, so the UI thread is occupied with your work, not responding to changes and updating itself. You have to execute your code in a background thread. –  Nov 08 '17 at 21:29
  • long-running operations should _never_ be executed in the UI thread. Use e.g. `Task.Run()`. Then, you can await the task and interleave UI updates as needed. See marked duplicate for examples. – Peter Duniho Nov 09 '17 at 02:07
  • Thanks! I'm new to C#/WPF and wasn't thinking of the main thread as the UI thread. Most of my attempts were to send the Messenger to a different thread, but it's so obvious now why that doesn't make sense. Once I update my code, I'll post my own answer so that this question is still useful to someone. – user438461 Nov 09 '17 at 14:34

1 Answers1

-1

Don't call a method who take several time in the UI thread.

You can try by created a custom window. In this you can show all custom information for your user. As your method take several time, you can add a cancel button for exemple. You can also add a progress bar. When a method take time, it's great to know the state of the system.

Try this, when you press your button -> call a command to lunch a thread

In your command :

void Command()`
{
    // run a thread, create a window and show it
    // you can declare the thread outside if you want use something like join
    Thread threadExecute = new Thread(Execute);
    w = new WinTest();
    w.Topmost = true;
    w.Show();
    threadExecute.Start();
}

// Call when your thread terminated
void finish()
{
    w.Close();
}

void Execute()
{
    // Your big method 1
    // Change the window information
    // big method 2
    this.Dispatcher.Invoke( finish );
}
Nymau
  • 134
  • 1
  • 9