Multithread problem.

Topics: CAB & Smart Client Software Factory
Jul 25, 2006 at 10:35 AM
originally posted by: JKraft4PIT

I have a view (V), presenter (P), workitem (W) and service(S).

The W shows the V and the P is injected using "CreateNew" in the V.
The S is injected using a "ServiceDependency" in the P.

All things work great but my services are set up like so.

When I need data from a service it creates uses reflection to get the data. To get the data back from the service it is a event that fires with data as a argument.

(example to clarify)

'P code
private sub GetDataFromService
call myservice.GetInfo()
End sub

Private sub Datareceived(sender as object, args as dataeventargs) handles myservice.DataReturnedEvent
'how do I get on UserInterface thread?
call view.ShowData(args.data)
end sub

The "DataReturnedEvent" returns on a diferent thread then the UserInterface so I am getting a cross threading exception.

I can take the args.data and push it into the state and then captuer the state changed event on the view and have it fire on the userthread and that worked fine. But now I need to be able to do things from the presenter.

How do I get onto the UserInterface Thread? Is there something I can use that is built into CAB?
Jul 25, 2006 at 12:10 PM
originally posted by: ChrisHolmes

Why are you returning data from a service using an event handler? Why can't you just have the service method return the data like normal? I'm not versed with VB.net so unsure what it can/can't do.

In C# we would just have the method call return the object:

DataObject = Service.GetInfo();

Then shoot it off to the view:

view.Update(DataObject);
Jul 25, 2006 at 12:42 PM
originally posted by: JKraft4PIT

That would be how you usually do it but I am using the Offline Application Block it does things differntly.

You ask for data and handle a event when the data is returned. This keeps the UI from locking up, but introduces the Cross threading problem.

The "Service.GetInfo()" returns a reference to the request (a GUID).

This is what happens without getting to specific.

1. Service.GetInfo() generates a request.
2. The request goes in a queue. (inMemeory, could be a databse or isolated storage)
3. A queue manager looks in the queue and tries to fulfill the request. (get data from web service using online proxy)
4. Fulfill request and returns the results back to a service manager.
5. The service manger finds the service that made the request and raises the event on the service. (public sub datareturned..... handles Service.Datareceived)

Since all this happens async it is returned on a differnet thread each time.
Jul 25, 2006 at 1:04 PM
originally posted by: ChrisHolmes

I get it. Offline application block. Gotcha.

Ok, you were on the right track when you wrote:

"I can take the args.data and push it into the state and then captuer the state changed event on the view and have it fire on the userthread and that worked fine. But now I need to be able to do things from the presenter."

You can still subscribe to the StateChanged event from the Presenter. Or, you can fire your own event when you receive the Event argument data. Either way, the Presenter can respond and then send the data to the View for update. The view doesn't have to do that work.

You're close =)
Jul 26, 2006 at 5:03 AM
originally posted by: JKraft4PIT

That is what I already do. I have been reading that using state on objects that dont need to persist isn't the best practice so I would rather do this call..

//ill write in C# so easier for you
//I would rather do this call
public void InfoReturnedEvent(args)
{
view.ShowData(args.data)
}

//But I am doing this call instead
public void InfoReturnedEvent(args)
{
state.RaiseStateChangedEvent("Info",args.data,nothing);
}

//viewcode
StateChagnedEvent("Info",Userinterfacethread) //Don't know exact syntax in C# but opens on UI thread
public void InfoChagned(Object sender, StateChagnedEventArgs args)
{
Info tempInfo = (Info)(args.newvalue)
this.ShowData(tempInfo)
}

The first section of code is one line to start manipulating the view instead of creating a state, raising a event that it changed, capturing that event, casting the argument data to my object type, then calling the fuction to update the view. Just seems like alot of work to get onto the UI thread and do some work.
I know how to do a Invoke on the view to get back on the thread but I am not sure how to check which thread to be on. Maybe I am missing something.

//general invoke but where do I put it? and how do I check whic thread I am on and which one I want to be on?
view.invoke(ShowDetail,object() {sender,args});
Jul 26, 2006 at 5:41 AM
originally posted by: JKraft4PIT

Okay I have used View.Invoke fine and don't need the state raised event which is great since it is now faster.

I found out that there is a view.isinvokerequired, and when true I do a invoke otherwise I don't. I also only do this in the view since I read that this is where the thread switching should occur and not in the presenter.

I have now come across a differnent problem. If you want to see my solution code I can show you. I use it everywhere since pretty much all data returns on a different thread.