Screens, Conductors and Composition

Topics: Getting Started
Nov 21, 2013 at 1:11 AM
Cheers for CM - It's really great. I am building an application based on the Billy Hollis model used in the CM Training example. My application is quite advanced and has 10 screens rather than the 3 basic screens in the example. My latest issue is how to work with one screen from within the view model of another screen. For a simply stated example, suppose that while working the original CM sample - - - in the "Orders" screens view model of the example, you needed to call the "Customers" Master screen. (Easy, you just click the Customers Icon) - - - but no - - I need to call the customer master in code from the orders view model. Seems like it should be so easy but, so far it has me stumped. Can anyone help to show me how.
Thanks a lot!
Nov 26, 2013 at 12:44 AM
This is the perennial drill down question. You have a screen that uses foreign key references to other tables e.g. an orders customer number. You need to pop a customers view to choose a customer from a list or create a new customer for the order that you are editing / creating. And just to complicate matters, the customer may also have a foreign key to a sales district that may or may not exist and then the sales district may have a foreign key to some other tables record that either does or does not yet exist and its turtles all the way down.

I have never seen an answer to this question answered in any of the MVVM books that I have read and in any of the mvvm forums that I have perused. The solution to the problem is further complicated in that a customer may be a foreign key in many tables within an application. e.g. Orders, Invoices, Receipts, Credit Notes, Wip etc.

So back to the orders screen, should it be instantiated with only the direct foreign key viewmodel factories as it may need (say just customer). And should customer be instantiated with only its direct foreign key required viewmodels . Or should every viewmodel carry a chain of foreign key viewmodel factories all the way down to the very lowest that may be required. The second option, is taken, would create construction injector nightmares.

An approach to take is to pass the IoC into to each viewmodels constructor and allow the instantiation of any foreign key viewmodel as either a lookup datagrid or edit/ create usercontrol. This then keeps the complexity to one level of foreign key referencing per parent viewmodel.

Problem is that according to Mark Seeman and others the use of an IOC as service locator is seen as an MVVM anti-pattern and is to be avoided and I agree! So does this mean that MVVM is actually an impossible pattern to properly implement.
Nov 26, 2013 at 4:25 PM
Thanks Mark, I really did not realize when I phrased the question that I may be dabbling with one of the worlds oldest questions. You are absolutely right! The road to programming Hell is paved with a chain of view model factories. But alas, even though I may be a pragmatic albeit naïve coder, I think I can keep my wits about me and avoid straying into the abyss of anti-patterns. I do thank you and Mark Seeman for the "heads up" however to the possible implications of my deviant excursion.

Now if you or someone else (whose programming morals are loose enough to remain in good conscience, when helping someone stray from the edge of purity) would show me how to "pass the IOC to the Orders constructor" so that I can open the Customer Index, I absolutely promise that I will not drill down in the Customer chain, but instead will just grab one customer from the index and add it to the Orders.

Seriously, what I really need is this. In the Screens Sample, here at the CM site, add a button to the Orders Master and call it "ShowCustomer". So I need the code that one would add to the ShowCustomer button proceedure to successfully open the Customer Master.

Bob Ranck
Nov 26, 2013 at 9:51 PM
Indeed Bob!

Rather than fill this thread with deep and meaningless techno babble, may I suggest that you Google "hierarchical viewmodel". It should suffice for Orders with customers.
However, Caliburn IoC is a static class whose Get<> method is visible from all turtles.

Nov 27, 2013 at 1:23 PM
I fully expected that the IOC was visible, but am at a loss as to what the specific code should be. BTW, what exactly is a turtle?

Alas, I am a person who learns best from code example, the reason that I came to this forum is to learn how to open the Customer Master from within Orders. "Hierarchical ViewModel" is interesting and may one day be relevant but my immediate issue is to learn how to show the Customer Master from within Orders, So if you or some kind person could simply post some code here in this thread, which illustrates how to show the Customers Master from a button called ShowCustomer in Orders, it would really enlighten me.

Thanks, Bob
Nov 27, 2013 at 10:09 PM
From wikipedia
"Turtles all the way down" is a jocular expression of the infinite regress problem in cosmology posed by the "unmoved mover" paradox. The phrase was popularized by Stephen Hawking in 1988. The "turtle" metaphor in the anecdote represents a popular notion of a "primitive cosmological myth", namely the flat earth supported on the back of a World Turtle.

In you bootstrapper register an interface.
container.PerRequest<ICustomersViewModel, CustomersViewModel>();

Create the class as.
CustomersViewModel : Screen, ICustomerwViewModel

In the constructor for the OrdersViewModel pass in by constructor injection the IWindowManager windowManager
store this in
private readonly IWindowManager windowManager

In the method, in the same class, that the button is to use to raise the customers dialog use the following code
ICustomersViewModel viewModel = IoC.Get<ICustomersViewModel>();
// optional depending on need
// raise the window

The method described above should have the same name as the x:Name of the button, so that the button and the method can be tied together by Caliburn convention.

You will need to the pass IEventAggregator in the constructor as well to be able to publish an Event that the OrdersViewModel is listening for.
In the setter of the public property "string CustomerNumber" that contains the value that you want to transmit back to the OrdersViewModel, use this.eventAggregator.Publish(new PassCustomerNumberEvent(this.customerNumber));

PassCustomerNumberEvent is just a public class of containing a string field in its constructor, that is exposed by a public string property of whatever name you wish to use, that will be visible to classes that receive an instance.

OrdersViewModel will need to implement IHandle<PassCustomerNumberEvent> in a specific Handle method and subscribe itself to the eventAggregator thus
this.eventAggregator.Subscribe(this) so that it can receive and process the events published by CustomersViewModel

I hope this helps.
Nov 28, 2013 at 12:03 AM

Many thanks, I have not had a chance to implement it yet but I think you just gave me exactly what I needed. I wont have a chance to work on it tomorrow as its Thanksgiving Holiday, but hopefully I can get back to it over the weekend. CM is so elegantly simple, yet there is still a moderately sized learning curve, and since we are dipping into the IOC here a bit, I will need to methodically translate each of your instructions.

So yes indeed, I have more to give thanks for on this Holiday.