-1

I have Window 1 in which on button click i am opening Window 2 in new thread. Following is my code

 private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        Thread thread = new Thread(() =>
        {
            Scanner w = new Scanner();
            w.Show();

            w.Closed += (sender2, e2) =>
            w.Dispatcher.InvokeShutdown();

            System.Windows.Threading.Dispatcher.Run();
        });

        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }

Window 2 has form I am getting form values on Button click

 private void EnterProduct(object sender, RoutedEventArgs e)
    {
        var data = ProductDetailsData;
        LoadCurrentBetween objMain = new LoadCurrentBetween(); //new MainWindow();
        objMain.fillorderform(data);
    }

on button click of window 2 i am passing values of form to another View

public void fillorderform(dynamic data)
    {
        this.Dispatcher.Invoke(() =>
        {
            LoadCurrentdetails.Part = data.Part;
            LoadCurrentBetween loadCurrentbtw = new LoadCurrentBetween();
            Switcher.Switch(loadCurrentbtw);
        });          
    }  public static class Switcher
{
    public static MainWindow pageSwitcher;

    public static void Switch(UserControl newPage)
    {
        pageSwitcher.Navigate(newPage);
    }
}

Following code is giving error at "this.Content = nextPage;"

The calling thread cannot access this object because a different thread owns it.

public void Navigate(UserControl nextPage)
    {
        this.Dispatcher.Invoke(() =>
        {
        var aa = nextPage.Dispatcher.CheckAccess();

        this.Content = nextPage;
            });
    }

I have seen similar Questions asked by other developers but i am not getting how to fix. pls help

RackM
  • 449
  • 7
  • 26
  • Is there any reason at all to start the second window in a different UI thread? Besides that it makes your life harder, what is it good for? Better do background processing in a BackgroundWorker, or use Tasks. – Clemens May 15 '18 at 11:32
  • @Clemens Actually I want user to enter details in Window 2 , based on that I want to reflect changes at runtime to window 1 can it be possible with backgroundworker and tasks? – RackM May 15 '18 at 11:41
  • Even without that. Just create the second window instance and call Show(). A WPF application can have multiple windows, all operated by the same UI thread. – Clemens May 15 '18 at 11:43
  • @Jack as Clemens pointed out you can just call show(). the ui will handle threading for you. Its rare for you to ever need to do that yourself. As for real time changes, that can be easily handled multiple ways. Without know which changes you need to make I couldn't offer a particular solution, but the first step would be to not make your own thread to just call show. Then you can just decide how you want to pass messages back to the "Parent" window. – Hack May 15 '18 at 11:54
  • @Hack What is "the ui will handle threading for you" supposed to mean? There is a single UI thread that can handle multiple top level windows, that's all. No other "threading" is involved. – Clemens May 15 '18 at 11:59
  • @Jack Your windows should share a common view model class. Pass an instance of such a class to the DataContext of both your windows, and bind UI elements in the windows to public properties in the view model. That's the WPF way to exchange data between views. – Clemens May 15 '18 at 12:01
  • Thanks @Clemens yes only using show() will work. can you pleasesuggest how to share common view model to different views, I am new to wpf – RackM May 15 '18 at 12:07
  • Oh, there is *plenty* of information on the internet. Just google "wpf mvvm". – Clemens May 15 '18 at 12:08
  • @Clemens my concern is when user changes and data in Window 2 i want to reflect to Window 1 without replacing the full content of mainWindow – RackM May 15 '18 at 12:27
  • That's well possible with MVVM. – Clemens May 15 '18 at 12:27
  • @Clemens please suggest me to how to achieve that. I am using MVVM – RackM May 15 '18 at 12:37
  • I already did. Again, pass a single instance of a view model class to the DataContext of both windows. The rest depends on all the details you haven't mentioned in your question and that I don't know anything about. – Clemens May 15 '18 at 12:40
  • @Clemens That's essentially what I meant, I never said there were multiple UI threads. You call show, and it handles the rest, no need for creating a thread to essentially push something into the UI thread. – Hack May 15 '18 at 14:49

1 Answers1

1

WPF is very strict (compared to Windows forms) about requiring methods which update UI elements to be done on the main/UI thread. So you definitely want both windows to be in the main/UI thread. The error that you are seeing is what happens if you try to do UI work in WPF from a different thread, so you absolutely have to stop doing that. It's OK to have multiple windows open, all on the same UI thread.

If one of your windows is doing heavyweight processing that makes the UI lock up, then the easiest thing is probably to add the async keyword to your button click event, and put the work you are doing in another method which has an async keyword. Then, when you call the helper method, you use the await keyword.

I agree with others that BackgroundWorker and Task are two other ways to accomplish heavyweight processing in a background thread while still having a responsive UI. Tasks are easier to use than BackgroundWorker.

If you are using a BackgroundWorker, it may be good enough to use the RunWorkerCompleted event. If so, look at this post: How to use WPF Background Worker. If you are using a BackgroundWorker and you need to call a custom method in your UI class from the background thread, then pass the Dispatcher object for your window/dialog to the background thread (or get access to it some other way), and when it needs to call back into the UI, use Invoke with the Dispatcher object. By using Invoke, the method you are calling from the background thread will be executed on the UI thread.

Jean Libera
  • 549
  • 4
  • 8