-1

I have app that uses UI thread and another thread for executing operations in background, and updates UI with results from those operations.

This all works well. However, during one operation I need to ask from user to enter some value. Sequence:

  • UI thread running
  • Command -> 2nd thread started (lets call it working thread) that works in background
  • Working thread sends status information to UI while executing operations in sequence
  • During one particular operation, Working thread is stopped
  • A message is send that view must be shown, in order user to select an option
  • UI thread subscribed to this type of message, so it displays a view
  • User completes selection, and closes the view
  • working thread receives user selection, and continues with execution
  • Working thread finishes

Code to start new thead:

Thread thread = new Thread(Convert);
thread.SetApartmentState(ApartmentState.STA); // avoid "The calling thread must be STA" exception
thread.Start();

Code to send status information from working thread to UI thread:

Application.Current.Dispatcher.BeginInvoke(
    System.Windows.Threading.DispatcherPriority.Normal,
    (Action<OperationStatus>)delegate(OperationStatus operation)
        {
            OperationList.Add(operation);
        }, status);

Code to ask user for confirmation:

In MainViewModel, during the execution of working thread:

// create ViewModel, that will be used as DataContext for dialog view
var vm = new SelectOptionViewModel(OptionList);
// subscribe to Close event, to get user selection
vm.Close += (s, e) =>
{
    _option = vm.SelectedOption;
};

AppMessages.DialogScreen.Send(vm);

In MainView, during the execution of working thread:

AppMessages.DialogScreen.Register(this, vm =>
    {
        SelectOptionView view = new SelectOptionView();
        view.DataContext = vm;
        // view.Owner = this; // raises exeption about cross-threading
        view.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
        view.ShowDialog();
    });

The problem is how to set the dialog view to be displayed as centered in parent view (MainView)? Setrting view.Owner to "this" is not possible, since "this" is created on UI thread.

What should I change here to center dialog view in my app, while preserving the order of sequnce defined?

Rahul Singh Chandrabhan
  • 2,531
  • 5
  • 22
  • 33
Goran
  • 6,328
  • 6
  • 41
  • 86
  • I cannot understand what thred executes registered labda where dialog is created. It must be UI thread. If you need to run dialog in sync with working thread use Dispatcher.Ivoke method. – Pavel Voronin Aug 31 '12 at 21:25
  • Currenlty it is the worker thread that creates it. If I wrap it into the Dispatcher.BeginInvoke, how can I pass the result of this dialog to worker thread? – Goran Aug 31 '12 at 21:48
  • Hi voroninp, can you post "It must be UI thread" as answer, so I can accept it? It solved the problem. I was able to return value with Func function – Goran Aug 31 '12 at 22:00
  • Does this answer your question? [How to deal with cross-thread access exceptions?](https://stackoverflow.com/questions/11923865/how-to-deal-with-cross-thread-access-exceptions) – Peter Duniho Apr 27 '21 at 05:18

2 Answers2

1

Have you considered using a background worker?

Paul Michaels
  • 16,185
  • 43
  • 146
  • 269
  • I am not sure that I understand what difference would BackgroundWorker bring? At some point I would need, while working on the Background worker thread, to create a new View, which means that I need to send a message to UI main form (from ViewModel), which runs on a UI tread. I am not even sure that I understand how would BackgroundWorker fit MVVM scenario? – Goran Aug 31 '12 at 19:43
0

What thread executes registered labda where dialog is created?

It must be UI thread.

If you want to execute some code in UI context and get the results back to the working thread you can use SynchronizationContext and Task

See the example here, please.

Pavel Voronin
  • 13,503
  • 7
  • 71
  • 137