1

I am new to wpf and multithreading. I have five UserControl, A-B-C-D-E and goes back to A

I'm trying to reload the userControl A when B is loaded.

public class Main{
    public List<Page> pages;
    public UserControl currentScreen;
}

public class Page
{
    public UserControl userControl;
    public String xamlUrl;
    public void Invalidate()
    {
        try{
            var th = new Thread(() =>
            {
                ParseUserControl(xamlUrl);
            });
            th.SetApartmentState(ApartmentState.STA);
            th.Start();
        }
    }

    void ParseUserControl(String xamlUrl)
    {
        Console.WriteLine("ParseUserControl" + Thread.CurrentThread.ManagedThreadId);
        string strXaml = System.IO.File.ReadAllText(xamlUrl);
        UserControl uc = (UserControl)System.Windows.Markup.XamlReader.Parse(strXaml);
        UserControlParsedEventArgs args = new UserControlParsedEventArgs(uc);
        Application.Current.Dispatcher.Invoke(() => UserControlParsed(args));
    }


    void UserControlParsed(UserControlParsedEventArgs e)
    {
        Console.WriteLine("UserControlParsed " + Thread.CurrentThread.ManagedThreadId);
        userControl= e.userControl;
        Main.getInstance().currentScreen = userControl; //this line here throws error

    }
}

The main idea is to have a thread parse the user control and after the user control is loaded, we send it back to the main screen to display.

However, I get this error : "The calling thread cannot access this object because a different thread owns it."

I'm thinking it's because the UserControl is created in different thread, but I already did UserControl uc = e.userControl.

I've checked the thread ID:

main is running on id 8 <----------------------
ParseUserControl is running on id 9           |---always same
UserControlParsed is running on id 8 <---------

so the UserControl in UserControlParsed belongs to thread 8 and supposedly can be used in main? I'm confused.

Mc Kevin
  • 962
  • 10
  • 31
  • Typically, other threads don't create UI elements, rather they just get the data ready. But even then, the data cannot simply be bound to the Gui thread if the data isn't marshaled correctly which just means the data must be on the same thread as the mainwindow. There's lots of different ways to ensure the data is on mainwindow thread which you can search google for. – JWP Mar 04 '16 at 04:05
  • If you were using proper data-binding (which you should be anyway, instead of creating ui elements in code-behind) then you could create view models in any thread you like and the ui would update itself automatically. – Mark Feldman Mar 04 '16 at 04:38

1 Answers1

2

According to this answer:

An element created in one (UI) thread can't be put into the logical/visual tree of another element which is created on a different UI thread.

Workaround Technique for mixing elements created on different UI threads:

There is a limited workaround technique, which may provide you with some ability to compose the rendering of an element created in one UI thread with the visual tree created in a different thread...by using HostVisual. See this example:

http://blogs.msdn.com/b/dwayneneed/archive/2007/04/26/multithreaded-ui-hostvisual.aspx

But that it a bit complex. You should pass parameters from background thread to UI thread and create UserControl at UI thread.

Community
  • 1
  • 1
NoName
  • 7,940
  • 13
  • 56
  • 108