Homde
Homde

Reputation: 4286

WPF multithreading

I'm scratching my head in trying to get the multithreading to work as I want in WPF

I have an object (with a singleton) called Manager which does alot of processing and lookups. I want it to run in a separate thread from the UI, The UI will call methods on Manager to do the processing and fire events that the UI should react to

I'm converting this app from windows forms where I dont think this was a problem since the textbox event was automatically fired in a different thread. Not so in WPF where everything seems to stay on the UI thread.

How do I make an object "live" in a different thread and then how do I call its methods. I tried spawning it to a new thread using this in the Window constructor

        Thread managerThread = new Thread(new ThreadStart(ManagerStartingPoint));
        managerThread.SetApartmentState(ApartmentState.STA);
        managerThread.IsBackground = true;
        managerThread.Start();

and:

private void ManagerStartingPoint()
    {
        ManagerSingleton.Manager = new Manager();
        MediatorSingleton.Mediator = new Mediator();
    }

On the textbox textchanged event I call Manager.SetItemText(e.Value) which logically should be called on the new thread right? Still when I type and the event triggers the UI "stutters" and typing in the textbox is affected. Do I need to call the method asynchronously or something?

Upvotes: 2

Views: 833

Answers (2)

Heinzi
Heinzi

Reputation: 172220

You are just creating these objects in the background; that doesn't really make a difference. You need to call your methods in the background:

public YourTextBox_TextChanged(...) {
    var bw = new BackgroundWorker();

    bw.DoWork += (sender, args) => {
        // do your lengthy stuff here -- this will happen in a separate thread
        Manager.SetItemText(e.Value)
    }

    bw.RunWorkerCompleted += (sender, args) => {
        if (args.Error != null)  // if an exception occurred during DoWork,
            MessageBox.Show(args.Error.ToString());  // do your error handling here

        // Do whatever you want to do after the SetItemText has completed.
        // We are back in the UI thread here.
        ...
    }

    bw.RunWorkerAsync(); // start the background worker
}

PS: Make sure your Manager.SetItemText method is thread-safe! Using background threads, it is quite possible that multiple instances of Manager.SetItemText run in parallel (if a second TextChanged event arrives before the first SetItemText has been completed).

Upvotes: 4

user1228
user1228

Reputation:

All you're doing is creating a new object on another thread. After you create the object, the thread completes execution and becomes idle.

Object instances don't "live" on threads. An instance is just a pointer to a structure in memory. Just because you create an instance in thread A doesn't mean that all methods in that instance will run on thread A.

What you want to do is create a class that you can call from any thread but which uses its own internally managed thread (or some such construct) to perform execution.

Your "manager" should encapsulate a thread, or use the ThreadPool, to perform your "processing." When done, the manager will have to communicate back to your UI (using the Dispatcher to marshall this communication back onto the UI thread) indicating it has completed execution.

Upvotes: 3

Related Questions