|
musefan wrote: can you do a version that explains why code behind in a WPF application View is bad
It's not necessarily bad. It just depends on the code.
Here's an example that might help explain it:
You are running a company that makes the iWidget - it's the latest, greatest, MP3 player. Now, you outsource the actual manufacturing of the components to third parties (the ViewModel). Your job is to assemble them together (the View). Now, you want to have fancy, schamncy wizzing window effects. You could outsource this to the component manufacturers, but it actually makes a lot more sense in this case for you to do it yourself.
And there you have the delineation of responsibilities in MVVM - the VM does the logicy, commandy stuff, while the view does the view related stuff.
|
|
|
|
|
Hello Ian,
Could I please you to help me with my problem?
I have this code in big method in my Silverlight application that uses WCF service:
private void F()
{
DatabaseServiceClient client = new DatabaseServiceClient();
client.GetSubsystemsByTestRunIDCompleted +=
new EventHandler<GetSubsystemsByTestRunIDCompletedEventArgs>(client_GetSubsystemsByTestRunIDCompleted);
client.GetSubsystemsByTestRunIDAsync(testRunID);
treeAdditionalInfo.Items.Clear();
foreach (string subsystemName in lstSubsystems)
{
TreeViewItem subsystemItem = new TreeViewItem();
subsystemItem.Header = subsystemName;
subsystemItem.FontSize = 14;
treeAdditionalInfo.Items.Add(subsystemItem);
}
List<KeyValuePair<string, List<TestLogSmall>>> lstFormsAndActions =
client.GetFormsAndActions(testRunID).ToList();
client.GetFormsAndActionsCompleted +=
new EventHandler<GetFormsAndActionsCompletedEventArgs>(client_GetFormsAndActionsCompleted);
client.GetFormsAndActionsAsync(testRunID);
...
}
The code in first 2 callbacks is this:
private void client_GetSubsystemsByTestRunIDCompleted(
object sender, GetSubsystemsByTestRunIDCompletedEventArgs e)
{
lstSubsystems = new List<string>();
if (e.Error == null && e.Result != null)
lstSubsystems = e.Result;
}
private void client_GetFormsAndActionsCompleted(
object sender, GetFormsAndActionsCompletedEventArgs e)
{
lstFormsAndActions = new List<KeyValuePair<string, List<TestLogSmall>>>();
if (e.Result != null)
lstFormsAndActions = e.Result;
}
I need to get the list after this call:
client.GetSubsystemsByTestRunIDAsync(testRunID);
And to get the list after this call as well:
client.GetFormsAndActionsAsync(testRunID);
How can I do that? What should I write?
Thank you in advance.
|
|
|
|
|
I think you're a little confused as to the workings of an asynchronous operation. Here's what you're doing...
F: "Ok, client, I want you to go get all of those subsystem thingies."
Client: "Sure thing, boss... I'll be right back."
F: "Good, now let's put those subsystems in the tree--"
Client: "Hold on! I haven't even left yet!"
F: "Where's my list of subsystems?"
Client: "Give me a #(%*&#ing minute to get it!"
F: "Ok, I guess there aren't any... Now, Client... Oh good, you're here."
Client: "Of course I'm here... You haven't given me a chance to leave yet!"
F: "Now go grab all of those forms and actions, ok?"
Client: "Fine... But it's going to take a few minutes to--"
F: "Good, now let's put the forms and actions into--"
Client: "That's it! I quit! Get your own #(*%&#ing actions!"
Now, here's what you want to be doing...
F: "Ok, Client1, I want you to go get all of those subsystem thingies."
Client1: "Will do."
* Client1 goes off to do his job
F: "Great... Now, Client2, you're going to fetch all of those forms and actions."
Client2: "Yep, I'm on it, boss!"
* Client2 goes off to do his job
* F makes sure everyone is gone, and turns on the TV to check the latest scores...
* Client1 and Client2 both return
* Client1: "All done. Here's the results."
* Client2: "Me too... Here's mine.
* F turns off the TV, grumbling about how he has to actually do some work
* F: "Alright, you first... Let's put these things in the tree......"
So you see, when you send the clients off to do something, that's called an asynchronous operation... Because they can do something on their own, and you don't have to sit there waiting for them to finish. Sending them off is your RunAsync() operation, whatever you want to call it.
The trick is that you're trying to read the results as soon as you send them away, instead of doing that after they come back. When they return with the results, that's the "GetSubsystemsByTestRunIDCompleted" event, in your example. THAT's where you should be processing the resulting data... In the handler for that event.
|
|
|
|
|
Ian,
Thank you very much for your answer.
I've understood Silverlight programming model was different than WPF.
If I understand you correctly, it's not possible to do the thing I need?
If so, it's not so good. My method is fairly long and complex. And the things are going in the loop as well. So, if I need to rearrange all these things, hm...
Is there any way to overcome this async style of doing the things?
|
|
|
|
|
Not directly know, and it is bad practice to consider doing it. You would, potentially, have to leave a long running connection open to a web server which would put a strain on resources.
Honestly, this is why desktop people shouldn't be writing web applications - the two disciplines are just too different.
|
|
|
|
|
Please don't hijack somebody else's thread. That's just impolite.
|
|
|
|
|
Hello,
I don't think it's impolite. It's normal communication between people. But, in any way, I won't do that in the future.
Regards,
Goran
|
|
|
|
|
It's not good form. The whole point of a threaded question is to answer the original posters problem, not to introduce something confusing into the mix. You have added nothing, other than a distraction, to the posters knowledge.
|
|
|
|
|
Again, not specifically WPF but ...
Most of the MVVM frameworks implement some sort of Messaging pattern to allow ViewModels to communicate.
Say VM1 selects a customer, it sends a "Customer Selected" message and VM2 responds to that message by displaying that customer's details.
All (that I have looked at) use a singleton Messenger object (the name varies) to which every VM has access and can subscribe to Messages or send messages.
And it all works fine and dandy.
Here's the bit I don't understand.
would it not be just as easy (if not easier) to use events? Isn't this just what the messenger is duplication?
So VM1 selects a customer and tells an "Eventor" singleton to raise the "Customer Selected" event. VM2 has subscribed to this event, and so displays that customer's details when it is raised.
I feel sure that there's a good reason for not doing this, but I'm stuffed if I can think what it is?
(Just to show I'm not a complete doofus, I am aware that most Messenger implementations avoid potential memory leaks by using WeakReferences, which may be an advantage - but is that the only reason for using it?)
Thanks
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
_Maxxx_ wrote: (Just to show I'm not a complete doofus, I am aware that most Messenger implementations avoid potential memory leaks by using WeakReferences, which may be an advantage - but is that the only reason for using it?)
No, that's not the only reason - in fact, routed events use weak references internally as well.
_Maxxx_ wrote: I feel sure that there's a good reason for not doing this, but I'm stuffed if I can think what it is?
Decoupling. Purely and simply, decoupling. With event subscription you create an implicit hard relationship between the subscriber and the subscribee, so your ViewModels end up having knowledge of each other, which makes testing much more problematic. If you accept that one of the key tenets of MVVM is increasing testability then you see that having a mechanism that allows you to mock out the source of the "event" makes it much easier to test the VM.
I hope that helps.
|
|
|
|
|
I posted my question 7 minutes ago and still don't have a reply! send codez plz!
Wow - quick reply - thanks Pete...
Pete O'Hanlon wrote: . With event subscription you create an implicit hard relationship between the subscriber and the subscribee
true - but in my scenario the VM dosn't raise an event - it tells another (singleton) object (the equivalent of the Messenger which I called Eventor) to raise the event - so the only hard relationship is between VM and Eventor.
Pete O'Hanlon wrote: If you accept that one of the key tenets of MVVM is increasing testability
I do - and maybe that's where my knowledge is failing, as I haven't got my head around TDD yet.
Pete O'Hanlon wrote: having a mechanism that allows you to mock out the source of the "event" makes it much easier to test the VM.
Any reason why I can't mock something that raises an event just as easily as mocking something that sends a message?
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
Message/Event. It's up to you how you want to do it. A message is a lighterweight method of communication, so that's why it's popular. Have a look at what Marlon and I did in MefedMVVM[^] to see how we used a drop in Mediator for VM communication
|
|
|
|
|
Pete O'Hanlon wrote: Message/Event. It's up to you how you want to do it.
Ahhrghhh - don't tell me that! I want to be told "this is the best way to do it!" Now I need to go look at more stuff!
Pete O'Hanlon wrote: lighterweight
Some sort of boxing terminology?
Pete O'Hanlon wrote: Have a look at what Marlon and I did in MefedMVVM[^]
Noooo - more frameworks?!
Seriously, though, thanks for the help. I'm getting there.
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
Personally I try to avoid messages.
Yes, it gives a view model that is easier to write tests against, but it does it at a cost:
1) The compiler (and refactoring tools) are unaware of messages. Basic errors normally displayed at compile time are now runtime errors.
2) When debugging, the event's are typically delivered without any stacktrace showing where the call came from (at least in the toolkit I have been forced to use) making simple debugging operations complex.
Personally I find the price too high and I avoid using the messages. It would be nice if we could get weak event subscriptions though.
|
|
|
|
|
lmoelleb wrote: 1) The compiler (and refactoring tools) are unaware of messages. Basic errors normally displayed at compile time are now runtime errors.
That depends on the message type. If you use an enumeration for the message, then you get compile time checking. Yes, string based messages are prone to code smell.
|
|
|
|
|
Pete O'Hanlon wrote: string based messages are prone to code smell
Ah so now I have stinky code huh. I got the impression that Silverlight does not like enums, I think they did not cross from VM to View or something.
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
It can't be Silverlight per se - must be whatever MVVM Framework you're using. After all, an enum is just an integer by any other name.
Personally I was thinking (if I use messaging rather than events) of using a message class rather than a string- although the overheads of defining a class for every message seems like overkill to me...
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
_Maxxx_ wrote: It can't be Silverlight per se
I think it is SL as I ran across some issues trying to parse an enum in the code behind of a view and dropped enums from the SL app for this reason. I can't remember the details so I will have to do some more investigation.
Prompted by Pete's comments I will now spend some more time with enums. B/C of delivery pressures I tend to drop a problem issue for later investigation if there is a Q&D work around (strings fitted this area).
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
A few things I didn't see mentioned in responses:
1) In *proper* 100% by the book mvvm, ViewModels shouldn't known about each other. With that being said, how could they subscribe to events?
2) You could put all your message types in a central place for convenience. Or make static public members. Same thing. There are pros and cons to both.
3) I've never seen a messenger class with weak references. What framework was that in? Usually they do something like Messenger.GetMessage(messageType).Subscribe(callback) or Messenger.GetMessage(messageType).Handler += callback.
The one I wrote doesn't use weak references, but it handles "bad" handlers by removing the subscription. I think thats a bigger concern then mem leaks. Also, async is a big deal. No point in calling one callback and waiting for it to finish (most messenger classes I've seen do this!) before calling the next.
|
|
|
|
|
SledgeHammer01 wrote: ViewModels shouldn't known about each other. With that being said, how could they subscribe to events? Smile
They don't need to know about each other. VM1 has a reference to some singleton - let's call it Eventor. VM2 also has a reference to Eventor (in fact, all VMs have a reference to this singleton).
VM1 tells Eventor "Please let anyone who is interested know that I just selected this Customer" and passes the customer in question (or the ID as an integer, or something to identify the customer).
Eventor has a method LetAnyoneWhoIsInterestedKnowThatThisCustomerWasSelected()
This method raises the "CustomerSelected Event.
VM2 is a subscriber to this event, and so handles it.
VM1 knows nothing of VM2 which knows nothing of VM1.
SledgeHammer01 wrote: 2) You could put all your message types in a central place for convenience. Or make static public members. Same thing. There are pros and cons to both.
Yep - I started doing this using a Messenger implementation that used strings. Trouble was I wanted to pass around an IMessenger so didn't have access to strings in the concrete Messenger class (I was,perhaps, being pedantic using IMessenger though)
SledgeHammer01 wrote: What framework was that in?
I think MVVM Light does, as does MVVM Foundation
SledgeHammer01 wrote: handles "bad" handlers by removing the subscription.
Not sure I follow - how do you know they're bad??
SledgeHammer01 wrote: I think thats a bigger concern then mem leaks.
Not for me - I've worked on projects with big memory leak issues where events have been used across classes and have failed to be removed - over a period, memory usage can grind applications like this to a halt (in the instance to which I allude, the lookup Views failed to be garbage collected due to references kept alive by event handlers not unsubscribing)
SledgeHammer01 wrote: Also, async is a big deal. No point in calling one callback and waiting for it to finish
Good point - I guess if several VMs subscribe to a message/event or whatever, firing their handlers asynchronously would be sensible in most cases - but how would you do that? One thread per handler?
Thanks, SledgeHammer, for taking the time to respond - I'd be interesting in seeing your framework if it is available for public perusal.
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
_Maxxx_ wrote:
They don't need to know about each other. VM1 has a reference to some singleton - let's call it Eventor. VM2 also has a reference to Eventor (in fact, all VMs have a reference to this singleton).
VM1 tells Eventor "Please let anyone who is interested know that I just selected this Customer" and passes the customer in question (or the ID as an integer, or something to identify the customer).
Eventor has a method LetAnyoneWhoIsInterestedKnowThatThisCustomerWasSelected()
This method raises the "CustomerSelected Event.
VM2 is a subscriber to this event, and so handles it.
VM1 knows nothing of VM2 which knows nothing of VM1.
Yeah, so you need to do a lot of stuff manually (from your description -- unless I misunderstood). To me it sounds like Messenger is a more organized / compact / cleaner solution. Nobody needs to keep a ref to anything.
_Maxxx_ wrote:
Yep - I started doing this using a Messenger implementation that used strings. Trouble was I wanted to pass around an IMessenger so didn't have access to strings in the concrete Messenger class (I was,perhaps, being pedantic using IMessenger though)
In most of the frameworks I've seen, a singleton Messenger instance is exposed somewhere. What I did in mine was make it a "service" (as in the service locator pattern) and make the ServiceLocator a public static member of ViewModelBase:
IMessengerService msg = ViewModelBase.ServiceLocator.GetService<IMessengerService>();
_Maxxx_ wrote:
I think MVVM Light does, as does MVVM Foundation
I'll have to check it again. Last time I looked, I think they were strong refs, but it was a while ago, so maybe I'm confused. I looked at a lot of frameworks before I did mine.
_Maxxx_ wrote:
Not sure I follow - how do you know they're bad??
I handle the case where they throw an exception and report it. Another case is where they hang, but I don't handle that case. A possible solution might be a timeout mechanism or something.
_Maxxx_ wrote:
Not for me - I've worked on projects with big memory leak issues where events have been used across classes and have failed to be removed - over a period, memory usage can grind applications like this to a halt (in the instance to which I allude, the lookup Views failed to be garbage collected due to references kept alive by event handlers not unsubscribing)
Well, w/ messenger you'd only have that problem if something is continously being re-created and resubbing. If your views only get created once and you sub once, well, you aren't going to really "leak".
_Maxxx_ wrote:
Good point - I guess if several VMs subscribe to a message/event or whatever, firing their handlers asynchronously would be sensible in most cases - but how would you do that? One thread per handler?
I don't create seperate threads because that would make GUI calls a pain. I get the callback invocation list and enum through and call them asynchronously. In the callback completion I catch any exceptions and report / unsub them.
_Maxxx_ wrote:
Thanks, SledgeHammer, for taking the time to respond - I'd be interesting in seeing your framework if it is available for public perusal.
Sorry, its part of my "bag of tricks" assembly. Plus, I don't really have patience to support it. I figure everbody was going with mvvmlight or cinch. I just wanted to write something light weight and understand ever line of code . Plus it was a good way to learn mvvm .
|
|
|
|
|
SledgeHammer01 wrote: you need to do a lot of stuff manually (from your description -- unless I misunderstood).
I think you misunderstood - although as I haven't written it yet, you may well be right
SledgeHammer01 wrote: I don't create seperate threads
SledgeHammer01 wrote: call them asynchronously.
Isn't an asynchronous method running on a different thread?
SledgeHammer01 wrote: Sorry, its part of my "bag of tricks"
No probs.
SledgeHammer01 wrote: I figure everbody was going with mvvmlight or cinch
.. or one of the seventy-eleven other frameworks
SledgeHammer01 wrote: something light weight and understand ever line of code
Exactly my aim - I don't want a Framework I want a methodology that I understand without 'black boxes'
SledgeHammer01 wrote: Plus it was a good way to learn mvvm
Again, just what I'm doing. - hence these odd questions from time to time.
Again, thanks for taking the time to respond.
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
SledgeHammer01 wrote: 1) In *proper* 100% by the book mvvm, ViewModels shouldn't known about each other. With that being said, how could they subscribe to events?
I thought that was stated implicitly by my statement: "With event subscription you create an implicit hard relationship between the subscriber and the subscribee, so your ViewModels end up having knowledge of each other, which makes testing much more problematic."
Hmmm, on rereading that I can see you're right; it didn't make it clear enough - even though that was the intention.
|
|
|
|
|
_Maxxx_ wrote: I feel sure that there's a good reason for not doing this, but I'm stuffed if I can think what it is?
The overhead (and the risk of potential memory leaks).
IMO, too many eventor's will be a hit on resources.
The funniest thing about this particular signature is that by the time you realise it doesn't say anything it's too late to stop reading it.
|
|
|
|
|
Abhinav S wrote: The overhead
Is an event a bigger overhead than a Message, then? (See, I'm clueless!)
Abhinav S wrote: the risk of potential memory leaks
Yes - that's the one that I fear most.
Abhinav S wrote: IMO, too many eventor's will be a hit on resources.
I'd anticipate only one Eventor - which is the equivalent of the singleton Messenger class - instead of routing messages it raises events - no great overhead (unless an Event carries more baggage than a Message)
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|