×

First time here?

You are looking at the most recent posts. You may also want to check out older archives. Please leave a comment, ask a question and consider subscribing to the latest posts via RSS or email. Thank you for visiting!

I got an email the other day about if there was a way to pass an object between the navigation pages in Silverlight 3.  The scenario was that the developer wanted to use the same data, but represent it visually in different ways.

Silverlight 3 introduces a new navigation framework in the runtime making it easier to navigate to different areas of an application and assist in ‘deep linking’ concepts for applications.  More resources:

At first my reaction was “no, we don’t allow that easily” but then I thought about it a bit and played around with a sample in the context of this developer’s use case.  Right now, the way you can quickly pass chunks of data to another page is via query string mechanisms.  So in my code I can say:

   1: myFrame.Navigate(new Uri("/foo.xaml?customerId=1234", UriKind.Relative));

And then in the navigated page something like:

   1: string customerId = this.NavigationContext.QueryString["customerid"];

This works fine for string/simple data.  In fact I could probably serialize a simple type and send it this way as well…but I don’t think that was the desired intent of this developer.  But if you think about the concept of the Frame, then you can start thinking about DataBinding techniques and how we can use the Frame as our container.  Allow me to think out loud…

Let’s use the default Silverlight Navigation Application template in the Silverlight 3 Tools for Visual Studio.  This will give us enough stub to work with.  If you look at MainPage.xaml you’ll see that the page has one Frame element in it:

   1: <navigation:Frame x:Name="Frame" Source="/Views/HomePage.xaml"
   2:       HorizontalContentAlignment="Stretch"
   3:       VerticalContentAlignment="Stretch"
   4:       Padding="15,10,15,10"
   5:       Background="White"/>

This is the core element that is going to receive navigation commands and change its content based on those commands.  Now in the Loaded event handler of MainPage, let’s grab some data.  I’m using a simple class here that just iterates a Person type (mainly so I can include it in the sample easily).  My Loaded event handler now looks like this:

   1: void MainPage_Loaded(object sender, RoutedEventArgs e)
   2: {
   3:     People p = new People();
   4:     List<Person> peeps = p.GetPeople();
   5:  
   6:     this.Frame.DataContext = peeps;
   7: }

So you can see that I’m now setting the DataContext of the Frame element to my List<Person>.  So now let’s crack open some of the other pages.  Again, remember the scenario: same data, different views.  Open the Views/HomePage.xaml and let’s show a view of just a simple list of names.  I added a ListBox and just displayed the FullName property of my data:

   1: <StackPanel> 
   2:     <TextBlock Text="Name List" Style="{StaticResource HeaderTextStyle}"/>
   3:     <StackPanel Style="{StaticResource ContentTextPanelStyle}">
   4:         <ListBox x:Name="PeopleList" DisplayMemberPath="FullName" 
   5:             ItemsSource="{Binding}" />
   6:     </StackPanel>
   7: </StackPanel>

Notice that there is going to be no code here in the source file for HomePage.xaml.cs – we are using the {Binding} property for the ItemsSource…essentially trickling down the DataContext from the Frame.  Remember, that HomePage.xaml is essentially a child control of the Frame so it is aware of the DataContext.  Now let’s go into AboutPage.xaml for our more detailed view, showing a DataGrid of all the elements of the data:

   1: <StackPanel>
   2:     <TextBlock Text="Detail" Style="{StaticResource HeaderTextStyle}"/>
   3:     <TextBlock Text="Detail list of members with gender." 
   4:             Style="{StaticResource ContentTextStyle}"/>
   5:     <data:DataGrid ItemsSource="{Binding}"/>
   6: </StackPanel>

Again, no code here to retrieve the data or wire it up – using {Binding} to the DataContext again.  So now with one data fetch and binding to our navigation context (Frame) we can re-use that same object across different views and the result shows us different levels of detail.

View 1: simple listView 2: detail list

So at least that is one thought of how to share the information.  What do you think?  Obviously it will not work in all scenarios, but also remember you can have more than one navigation frame in your application too!  Here’s the sample code for these thoughts: SilverlightApplication32.zip

Hope this helps!


This work is licensed under a Creative Commons Attribution By license.


4/3/2009 3:24 PM | # re: Share DataContext among navigation pages in Silverlight 3
You also might just have the data as part of your Application class. Make a public static property that exposes the collection and allows it to be shared thruout the app.
4/3/2009 3:26 PM | # re: Share DataContext among navigation pages in Silverlight 3
Wow - with all due respect (you're way smarter than I am), this makes me cringe. I've had some similar scenarios where I just do something to make it work, but there are so many ways that the datacontext could get corrupted (at best). This -might- be something Caliburn is capable of. I haven't played with it enough to know for sure.

All that said, it's an interesting solution.
4/3/2009 4:07 PM | # re: Share DataContext among navigation pages in Silverlight 3
Mark -- to be honest even when I was doing this 'thinking aloud' exercise I think it wouldn't be a mainstream case all the time. I think in a small scenario (again, as the one described here) where you wanted to provide somewhat of a master/details view spread across multiple pages, it might be okay to do this if that was the only thing that the navigation frame was responsible for. If the nav frame was an overall application-wide navigation handler, I don't think this would be a good solution.
4/3/2009 8:06 PM | # re: Share DataContext among navigation pages in Silverlight 3
Hum intrusting possibilities open up Where a view really is just that, a way to view some type of data. Say an IEnumerable List using datagrid and maybe attributes to describe what should be shown. And then when clicked on an individual record it could look up the type of that record in a master list of Type->Views. Allowing a very generic and cool kind a site, very easily extendable. Think of for instance a forum, which uses a datagrid view to display the forum topics, when someone clicks on a forum topic the exact same view comes up, but with a different datasource the threadlist, when someone clicks on one of the threads, it sees that a thread isn’t an IEnumerable<t> so it brings of the Thread view. Where you create views based not on application flow, but more on the type of data that they view.
4/3/2009 9:12 PM | # re: Share DataContext among navigation pages in Silverlight 3
This is a nice solution for small applications where you dont want to go the full Model View ViewModel route. Yet in the long run you might as well just be easier to and cleaner to have all the views bound to a viewmodel and then not have to worry about where the data is coming from.

just posted a quick blog on this

www.cynergysystems.com/.../michaelwolf

The navigation framework I think in naming makes it seem more web app like then it is (frame,source etc). Even though you are specififying a .xaml file as a url, its really a full fledged user control which participates in the full application.
4/3/2009 9:27 PM | # re: Share DataContext among navigation pages in Silverlight 3
Well viewmodels are just a type of data. A view using this could just be created for each "type of data" that you want to dispaly. If you start out with your .net ria services of a Linq2Sql database to start, as your datacontext (for small programs), and then easly move to a full viewmodel objects as needed. Having one view take care of say the "about us" page and the "contact us" page etc adds alot of intresting "master page" (from ASP.NET) kind of functionality.
4/3/2009 10:54 PM | # re: Share DataContext among navigation pages in Silverlight 3
On a somewhat different topic : Any updates on the Silverlight 2 Book ?
4/4/2009 1:05 AM | # re: Share DataContext among navigation pages in Silverlight 3
Very nice way to pull that off.
4/6/2009 4:53 AM | # re: Share DataContext among navigation pages in Silverlight 3
I was thinking about two other possibilities, although I never had a chance to play with them.

The first is to use a ViewModel that has access to shared data. Irrespective of the navigation frameworks/pattern used, this problem has been solved before (e.g. using MessageBroker, Events, ViewModel Hierchies (nested), etc or an IoC.

The second option is a bit different and specific to this Navigation FX. I wanted something that would work either when navigating from one View to the other (reusing in-memory data) or when getting directly to a different view model (deep linking/perma link).

The patter is simple. Both views will need to have access to a common containers and the child view will try get the data from there. In case it can't find it (e.g. the user navigated directly using a link), the view will go a get it.

This would be in a ProductListPage.
private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
var btn = sender as HyperlinkButton;
var productId = btn.Tag.ToString();
var product = btn.DataContext as Product;
kernel.Bind<Product>("SelectedProduct").To(product);
this.NavigationService.Navigate(new Uri(string.Format("Product/{0}", productId), UriKind.Relative));
}

And then in ProductDetailsPage
void ProductDetail_Loaded(object sender, RoutedEventArgs e)
{
var product = kernel.Get<Product>("SelectedProduct");
if (product == null && this.NavigationContext.QueryString["id"] != null)
product = ProductsService.GetProduct(this.NavigationContext.QueryString["id"]);
this.DataContext = product;
}


This is just a simplistic example, but the idea is there. In a real world app, I'd change the View to don't get directly the information from the Service, but rather delegate to a controller/presenter/viewmodel/datamodel, etc.
4/6/2009 7:44 AM | # re: Share DataContext among navigation pages in Silverlight 3
@At first my reaction was “no, we don’t allow that easily” but then I thought about it a bit and played around with a sample in the context of this developer’s use case.

Your example still doesn't allow it easily - it is just barely possible. However, it takes advantage of none of the core navigation subsystem features. You are effectively using a GOTO to solve this problem. Observe:

myFrame.Navigate(new Uri("/foo.xaml?customerId=1234", UriKind.Relative));

Frame.Navigate is GOTO for hyperlinks. Moreover, the frame has direct knowledge of navigation relationships. This is incredibly tightly coupled and does not scale.

At a more basic level, you are shaping the problem in an awkward way (which I don't blame you for, since you're trying to get a specific how-to tutorial point across). You state the problem as:

@The scenario was that the developer wanted to use the same data, but represent it visually in different ways.

For the most part, this is what REST is all about. You have a single resource, but one to expose multiple representations of that resource and have each representation be addressable. This just so happens to be a requirement for our application where I work, too.

The navigation framework as presently constituted, however, doesn't do a good job encapsulating these concerns.

Miguel is leaning in the right direction, but instead of the Frame having hardwired knowledge of the view and the next view, his frame is just a container for some sort of TransferAgent object (this.NavigationService). However, the pages themselves still have to be compiled and therefore located within an assembly. The view knows too much. I'm not sure how Miguel plans to "delegate to a controller/presenter/viewmodel/datamodel", though. To me, that still requires compiling pages, rather than merely decorating views with behaviors provided by toolkit subsystems.

A hyperlink really should be a decorator.
4/6/2009 8:10 AM | # re: Share DataContext among navigation pages in Silverlight 3
To better elaborate on what your theoretical requirements are for a good navigation framework:

1. Every object is a resource.

2. Every object therefore should be linkable (a REST principle).

3. Every resource can have multiple representations (a REST principle).

4. The Frame is simply a dumb container to host a composite part.

5. The Frame should have no knowledge of the navigation context, both at the application shell level and the composite parts level.

6. Hypermedia as the engine of application state (a REST principle): The Page's contents should only know about other resources and verbs for those resources. Adding a hyperlink to a Page on a Website, whether you think of it as an anchor tag's href or a form's submit action and destination, doesn't require you to compile-the-world.

7. By extension, a Page knows nothing about its container. In fact, in well-designed Web 2.0 applications such as Gmail, this is (for the most part) enforced through a hidden iframe element which acts as an InternalTransferAgent object, intercepting hyperlink requests, changing the view, loading any necessary new model associations, and mashing the two together. (I say "for the most part", because Gmail is minified and obfuscated. My comments are based on what Stephen Meschkat has indicated about its design. My hunch is it could be even better designed.)

This is a highly decoupled version of design requirements. Once you nail down highly decoupled, it becomes MUCH easier for Tools like Blend and Visual Studio to provide REAL project development tools. Not any of this code generation of typed datasets" RAD garbage. This allows these IDEs to truly promote drag-and-drop programming that is MAINTAINABLE. Stuff like partial classes are hacks and mostly horrible ideas that encourage IDE developers to stick with the same-old-same-od "software factories are about code generation" mantra.

Partial classes and stuff like that are like trying to use a paper clip to connect steel I-beams used to build a skyscraper.

Think at a higher level of abstraction than you've EVER thought of before!
4/6/2009 1:49 PM | # re: Share DataContext among navigation pages in Silverlight 3
I think this is a clever little method of sharing data across pages.
Of course, there are better alternatives but I like this method as a fast and as, possibly, a throw-away alternative for testing or prototyping purposes.

Because I've never thought of this way of binding, it forces me to think about the very intricate binding possibilities that may yet still be found and of other architectural cross-overs that never sprung to mind.

thanx, Tim.
Gravatar
4/6/2009 2:54 PM | # re: Share DataContext among navigation pages in Silverlight 3
I don't know what everyone is complaining about. What Tim said seems like common sense. I don't see how it's considered tightly coupled. It's not even an issue in my book and for the people that are complaining, I don't see them proposing a solution. If they are the masters of design patterns I guess they can implement their own pattern. I think the example would have made more sense if it had a list page and a detail page and used a CollectionView to keep track of the CurrentItem though.
4/6/2009 9:49 PM | # re: Share DataContext among navigation pages in Silverlight 3
Jon,

What you should be asking yourself is, will improvements in any way HURT you?

No, they wont.

In general, GUI toolkits progress toward two things:

1) making the view more model-friendly
2) making the model more view-friendly

Apart from navigation, WPF and SL pretty much let you place yourself wherever on this continuum you like.

Also, I am proposing a solution, and I am not using any explicit design patterns.

@I don't see how it's considered tightly coupled.

With "myFrame.Navigate", the myFrame object is a concrete reference to the page's container. Ask yourself, why do you want an artificial concept such as a Frame managing your conversation between your application and the user? Why stick in that dependency? Once you want to reuse the application feature outside its current context, you have to workaround that hardcoded reference.

I'm not saying, "yank that stuff from the API". On the contrary, many years of C++ has taught me that lots of people prefer going from a low-level of abstraction to a high-level of abstraction smoothly.

Also, it's not complaining. It's simply good design. In my experience, the people who say they don't need this abstraction today are the folks who clamor for it tomorrow.
4/6/2009 10:09 PM | # re: Share DataContext among navigation pages in Silverlight 3
Also, be deconstruct further (and directly answer Tim's earlier question):

@What do you think? Obviously it will not work in all scenarios, but also remember you can have more than one navigation frame in your application too!

Having more than one navigation frame "open" simultaneously basically wrecks havoc with your UriMapper. If you want, I can explain this in my usually deep analytical style, but I'm basically waiting for feedback at this point.

Again, I can write this myself (in fact I've basically given a pretty complete spec), but it just makes much more sense for it to be owned by Microsoft.
4/6/2009 10:25 PM | # re: Share DataContext among navigation pages in Silverlight 3
John -- where is there more than one nav frame open? This example here is leveraging only one navigation frame, that's it.
4/6/2009 11:08 PM | # re: Share DataContext among navigation pages in Silverlight 3
Tim, I'm quoting you. You mentioned the scenario, and I am pointing out it doesn't jive with UriMapper, because your UriMapper doesn't allow composition of state identifiers in the Uri. ;-)

I don't think this should be a supported scenario, though. We had a huge debate where I work about this.

I really do feel the fragment identifier system in Uri's is broken, though. Most hypermedia systems operate on a very static hypermedia model: they limit endpoints to concepts such as "points", "documents", or "cards". These are basically artificial concepts that serve no real purpose outside academia. If you think about it, these fixed set of concepts try to make the argument that material is more important than architecture - that's pathetic from a scalability standpoint. I guess that's why academics build only ivory towers.

The HTTP URI scheme is basically limited to documents and anchors (fragment identifiers). Anchors have no syntactic way to indicate nested substates or the combination of peer states. You could build a DSL within the anchor To paraphrase Alan Kay, This is what happens when physicists invent the Web.

I honestly think that is too much to ask for, though. At least for right now. Even I have my design limits. However, if you properly encapsulate UriMapping objects with UriPattern objects, it definitely gives you more room to "fiddle" with the "template" later on.
4/7/2009 6:47 AM | # re: Share DataContext among navigation pages in Silverlight 3
John,

I partially agree, but I think you're missing the point.
1. This is an example on how to share state with this Navigation Framework. There're alternatives of course, I proposed some, there might be others. I like Tim's? No, I think it's simplistic, I think we agree on this.
2. The Navigation Fx is hard to scale and wont' support view composition (at least is not clear to me atm), that's a separate topic, probably outside of the scope of this post. However I share your concern.

About your comments:

I don't think that having the dependency to a Frame or a FrameService it's a big deal. It would be better if we could easily mock it, probably yes. How big of a deal this is? I'm not sure, since my unit test might won't be at this level anyway. I would probably create an adapter and test my ViewModels (which will ultimately be responsible of the navigation). How I'm going to construct this in the VM, it gotta be hard, since I don't want to have to get it from the View :(

The fact that we're using anchors is just a current limitation of the browsers. I kinda like the idea of a mini-DSL within the anchor to support nested substates, although I'd have to analyse different scenarios to see if it's worth coming with a generic solution (at least for my usage) or other options like storing information in a user profile would do a better job. Most applications (web or windows) really don't handle this scenarios or they do it at a user/machine level.

To delegate to the ViewModel/Controller/Presenter I'd use an IoC Container, the View is composed with the appropriate object and will communicate the user's intention. Now how the V/C/P navigates to a different page I'm not sure. I've not used this framework in this context (or a real app for that matter), so this is a problem that I've not had to solve. Obviously there's a lot left to be said (or changed) and I'm sure Microsoft and other devs will come with the necessary changes or guidance to do this.
4/7/2009 7:15 AM | # Issues with Navigation
Tim,

Despite being exicted about implementing the new Navigation:Frame into my Silverlight app, I had a major issues with the fact that navigating to each page causes it to be reconstructed and reloaded each time it is visited. As a result, it does not allow you to retain each page's state (out of the box, that is). But since I really wanted the browser navigation, I had to work arund this issue.

Until I see a better solution, my navigation system of choice is to start with TabControl's with a custom look. Just like the way Picnik.com does in Flash. The nice thing about using TabControl's is that once each TabPanel loads, the state of the UiElements within each tab panel is retained.

So to work around the Navigation:Frame reload issue, I start by placing a single/hidden Navigation:Frame on my MainPage that acts as a traffic cop for app navigation. I keep it "hidden" with Height="1", and only use it to get the Browser history functionality. I do not place any content in this Navigation Page/Frame. Instead, I just catch the navigation events, and show/hide the tab content on my MainPage. In this way, I am be able to maintain the state of all my panel objects when switching between Tabs/Pages.

I created a small Navigation helper class and call it from my MainPage class as a bridge between it and my Navigation:Frame class.

And finally, I rely heavily on the UriMapping in my App.xaml to direct all navigation to the hidden NavigationPage, as in:

<Navcore:UriMapper x:Key="uriMapper">
<Navcore:UriMapping Uri="/{mainTab}/{subTab}" MappedUri="/NavigationPage.xaml?main={mainTab}&amp;sub={subTab}" />
</Navcore:UriMapper>

Obviously I would prefer to not to implement this workaround if you have any other suggestions. I could send you some code if it would help you understand the issue better.

Jim
4/7/2009 7:24 AM | # re: Share DataContext among navigation pages in Silverlight 3
John - we agree on state management.

Jim - maintaining state between navigation points is something we are looking at.
4/7/2009 11:25 AM | # re: Share DataContext among navigation pages in Silverlight 3
Miguel,

I can entertain a thought without embracing it. I'm sorry you think I'm missing the point, but what I'm actually doing is continuing where Tim leaves off in his posts. I don't have any insight into what Tim doesn't say, and I don't know what email conversations Tim is having with other developers. I prefer open, public communication for this reason. So I am saying what Tim is not saying, for whatever reason, to make sure that SOMEBODY says it.

I don't care if Tim wants the navigation framework to support the scenarios he is referring to. The developer is his #1 customer, and what they clamor for he has to respect, even if they clamor for a shot in the foot. Just so you know, it used to be that some Program Managers at Microsoft would ask customers, "Why would you need such a feature?" Then complaints were raised and now Program Managers are basically not allowed to ask this question, since it comes off poorly.

If people want to loosely encapsulate their navigation infrastructure, then let them! However, also let those of us who want hardcore separation of concerns and sound application structure partitioning to do it. This is what much of WPF and SL already does. The DataForm is a good example of a component that is flexible enough to allow for a wide variety of scenarios (although it too could be much better designed).

Some of the stuff I do is wizard-level programming. And all of it is an attempt to solve a real problem, not some ad-hoc "how do I do this?" scenario. Ad-hoc scenarios codified as objects in the domain often leads to too many permutations of look-alike objects. It makes much more sense to *stabilize the problem domain* and treat all the permutations with a small group of objects, rather than handling each on an ad-hoc basis. This is a much deeper design issue than "compile-the-world" vs. "plug-and-play hot swapping". At the object level, it is also a question of how you manage complexity and integrate systems.

I am a software developer for a company that has a portfolio of products, one of which is a 45 school (soon to be 50+ schools) School Information Services system. Within that industry, our clients pay for quality and fast turnaround time on feature requests. Not only do we have the best functionality in this niche industry, we also iterate faster than our competitors. As a tell-tale sign that we know what we're doing in the Software-as-a-Service space, *we've never lost a client*. None of our competitors can say that.

As our product's reputation continues to grow, so should we re-organize the complexity of managing N *highly customized* clients, where N is arbitrarily large. Right now we manage complexity pretty well, but we have both a Desktop and a Browser application and that equates two two codebases. Keeping feature parity between the Desktop and the Web is a royal pain and a money sink. We see WPF and Silverlight as a way to unify our codebase, perhaps even going wholy to Silverlight.

Not only that, but the same codebase for the Desktop and the Web is *100% reused* for our Hospital Billing Analysis and Claims Reimbursement engine and our Accounting package we sell in separate product divisions at our company. The only difference is the domain.

Quite frankly, good design decisions I make go into my bonus. I'm a professional API designer and the secret to success is nothing less than perfection.

Why am I sharing this? Because Silverlight is "new tech" and will be dominated in the adoption curve by young programmers. The most significant thing about young programmers is that they lack the experience in this area and don't know why certain things are important. As a result, they just assume it's not necessary. The reaction of those who don't understand my motivation is either apathy or confusion, a kind of "what are you after here?" type of thing.
4/7/2009 11:32 AM | # re: Share DataContext among navigation pages in Silverlight 3
@To delegate to the ViewModel/Controller/Presenter I'd use an IoC Container, the View is composed with the appropriate object and will communicate the user's intention. Now how the V/C/P navigates to a different page I'm not sure.

Navigating to different pages is the responsibility of an "Open Link Service". On some level, MSFT P&P employee David Hill's Helix framework for SL2 was supposed to support open linking, but it didn't. Most of these ideas were fleshed out over two decades ago. For instance, Sun's Link Service, MICROCOSM and Guide were three of the big hypermedia academic projects of the '80s. More recently, in the late '90s two uber-bright Ph.D. candidates at UC-Irvine wrote arguably two of the most important Ph.D. papers on hypermedia in the past 20 years. You probably already know Roy Fielding, aka "the REST guy". The other guy was James Whitehead, aka "the WebDAV guy". The point here is that these navigation questions are "solved problems", and they also are prime for wide adoption by the programming community.

And because they are solved problems, they are ripe for a "platform company" like Microsoft to own.

No VB programmers threw themselves out the window of their office building when Paul Vick announced VB was getting lambda expressions. Likewise, a correctly designed Object-Oriented Hypermedia platform won't cause programmers to want to cut off their fingers and go on social welfare disability.

@I don't think that having the dependency to a Frame or a FrameService it's a big deal. It would be better if we could easily mock it, probably yes. How big of a deal this is? I'm not sure, since my unit test might won't be at this level anyway. I would probably create an adapter and test my ViewModels (which will ultimately be responsible of the navigation).

By adapter on your ViewModel, you're basically referring to the Object Mother xUnit testing pattern. I feel this testing pattern is a code smell. It makes more sense to push complexity into an objects that represent the problem domain instead of hijacking the application harness (Frame) as a domain object for navigation.
4/8/2009 4:04 AM | # re: Share DataContext among navigation pages in Silverlight 3
Hi,

What happends if my page refreshes and the Frame is reloaded . In that case will the datacontext be existing ?

Thanks,
Thani
4/8/2009 10:02 PM | # re: Share DataContext among navigation pages in Silverlight 3
@John,

When I say you're missing the point, is because you're mentioning flaws of the Navigation Fx in general (which are valid), when this post is about how to share the Data between pages, that's why in my posts I was focusing on how to share data only (assuming I was using this Navigation Fx).

As I mentioned I partially agree with and I understand your concerns.

@how the V/C/P navigates to a different page I'm not sure
I mean, how's the V/C/P going to get a reference to the NavitagionFramework/Frame, without it beeing bound to UI controls. Later in the post I suggested handling an adapter.
The other thing I don't like a lot (and I'm missing the point of the post too :)) is the routing it's pointing to a view, which might need to point to an action which my controller might decide to do something about (e.g. save a file, do a different request, navigate to another page or website, etc).

@Adapter
I'm just talking about the Adapter Design Pattern, which will allow us to decouple our VM/C/P from the View, hence making it easy to test.
4/9/2009 7:00 AM | # re: Share DataContext among navigation pages in Silverlight 3
I think you are using the wrong design pattern.

Adapter pattern serves many purposes, but mainly it is to cover boilerplate required by a third-party library. By enforcing your developers use adapters, you stabilize the interface you depend on and disallow combinations of the vendor's API that your experiments and prototypes and analysis have shown to be crappy implementations.

The metaphors you want are Mediator and Observer.

You can fully decouple the Observer from the Subject in a publish/subscribe system by putting in a Registry object inbetween the two. The two objects then communicate by anonymous drops. You cannot get any further decoupled than anonymous drops. However, most anonymous drops vary in how they tag what is being dropped. This is the airport baggage metaphor. If you need to, you can always wrap your package in another package and tag that with a *surrogate key*.
4/9/2009 7:39 PM | # re: Share DataContext among navigation pages in Silverlight 3
I think having a mediator or observer would be introducing innecessary complexity. I'd still go with the adapter or proxy, specially for simple scenarios where the C/P/VM are responsable of all the navigation.

In an application with many frames/parts it might make sense to publish a message and different subscribers doing something about it (displaying different views in different frames, executing an action, etc), so I reckon Observer or MessageBroker might be a good option too.

Time to go and write something.
4/9/2009 8:24 PM | # re: Share DataContext among navigation pages in Silverlight 3
Gentlemen, allow me to suggest another shared DataContext idea, one of you might have mentioned it in above.

Currently I have a static "DataCache" object on my App class which I initialize in the startup.

public partial class App : Application
{
public static DataCache DataCache { get; set; }


private void Application_Startup(object sender, StartupEventArgs e)
{
App.DataCache = new DataCache();
this.RootVisual = new MainPage();
}

My DataCache object holds a reference to all of the ViewModels I have (One for each page).

public class DataCache
{
public Page1ViewModel Page1ViewModel;
public Page2ViewModel Page2ViewModel;
public Page3ViewModel Page3ViewModel;
}


In the constructor of each Page class I set the DataContext to the appropriate ViewModel.

public Page1()
{
InitializeComponent();

if (App.DataCache.Page1ViewModel == null)
App.DataCache.Page1ViewModel = new Page1ViewModel();

this.DataContext = App.DataCache.Page1ViewModel;
}

If I wanted Page2 to share the same DataContext, then I would set its DataContext to page1's ViewModel.

public Page2()
{
InitializeComponent();

if (App.DataCache.Page1ViewModel == null)
App.DataCache.Page1ViewModel = new Page1ViewModel();

this.DataContext = App.DataCache.Page1ViewModel;
}

Now I am not happy with the hardwiring of my ViewModel to my View, but I can't seem to be able to Inject my ViewModel
into my View. Tim what I would like to be able to do is pass the ViewModel into the View via the navigation code below.

private void NavButton_Click(object sender, RoutedEventArgs e)
{
Button navigationButton = sender as Button;
String goToPage = navigationButton.Tag.ToString();

if (App.DataCache.Page1ViewModel == null)
App.DataCache.Page1ViewModel = new Page1ViewModel();

this.Frame.Navigate(new Page1(App.DataCache.Page1ViewModel);
}

And in the constructor of Page1 I could accept the ViewModel and set the DataContext.

public App.DataCache.Page1ViewModel ViewModel;

public Page1(App.DataCache.Page1ViewModel pvm)
{
InitializeComponent();
this.ViewModel = pvm;
this.DataContext = this.ViewModel;
}

This is the current DataContext pattern I am using after reading up on Prism2. But with the new navigation framework
in SL 3.0 Beta, I am stumped on how to go about this.

Ideas?
4/11/2009 12:14 AM | # re: Share DataContext among navigation pages in Silverlight 3
Terrence,

You are passing concrete object references around your application. Your question is then how you can know what state the application is in so that you can deep link it with a Uri. The short answer is that you can't mathematically succinctly do this, because you are tightly coupled. In order to continue down your current path, you would need to know the state of your application at the point in which you changed it, and then mess with the Uri.

I'd refactor. Maybe it's "too late", in which case you can support Google Maps style permalink functionality, and have a button that based on certain key variables, is used to decide s URI fragment identifier for your application state. You can also cheat by storing additional state in isolated storage, but now your application is locked down to a user's single device, and the URI can't be accessed from anywhere.

Another solution is to use an inversion of control container to pass the references. This is the path of least resistance, and most IoC containers like Autofac allow you to map Page1 to a Page1ViewModel. Autofac in particular allows "scoped guards" you can use for this person. This will allow you to squish out your application, but won't make it maintainable.

However, there will be certain cross-page problems you will experience. Most IoC containers arent "web layer aware" (Java parlance) which means they are not stateful Passing state between these pages will require brute force effort. As I've already said, dependency injection doesnt make ad-hoc design not ad-hoc.
4/11/2009 12:24 AM | # re: Share DataContext among navigation pages in Silverlight 3
Miguel,

Broker is an overloaded term. I wouldn't equate Broker to Observer, or even Broker to Mediator.

In my vocabulary, Broker usually implies callbacks. I.e., "*Return_to_broker* to decide next processing step" - a tightly coupled workflow system. A mediator should not be that monolithic, and an observer strictly listens to notices published by a subject, and that's that.

A proxy is an Object Mother pattern: mocking one object with a mock object to test and isolate a component. To me, that implies that how the user interface and the data model interact isn't well-known, so unit tests are required. However, the control over specification these unit tests is illusory and can't be re-used as-is for free when you have similar model-view interactions.
4/15/2009 4:41 PM | # re: Share DataContext among navigation pages in Silverlight 3
Hi Tim
I have been using this method, for this exact same reason before and after SL3. I use a data object as the engine for my mechanical system simulator. This make it so easy to delay the download of a view, drop it into the parent and use TwoWay data binding for the communication. My DUC (Dynamically loaded UserControl) no nothing about it parent.
This is just so simple and clean

Glad to see someone else use it.
Thank for all your work
Mike
4/27/2009 3:32 PM | # re: Share DataContext among navigation pages in Silverlight 3
Nice post...
4/30/2009 3:37 PM | # re: Share DataContext among navigation pages in Silverlight 3
Hi Tim,
How integrate SL3 application with MOSS 2007?
4/30/2009 4:37 PM | # re: Share DataContext among navigation pages in Silverlight 3
Andrzej - same way you would a Silverlight 2 application...just use the Sharepoint kit or a content editor web part with the object tag.
7/27/2009 5:22 AM | # re: Share DataContext among navigation pages in Silverlight 3
Don't throw rocks, but how bad does this sound:

Make all the View pages inherit a System.Windows.Controls.Page (CustomBasePage) that holds instance and access to the object you wish to share and an overridden OnNavigatedFrom method doing:

CustomBasePage destinationPage = e.Content as CustomBasePage;
destinationPage.sharedObject = this.sharedObject;
Gravatar
2/9/2010 1:29 AM | # re: Share DataContext among navigation pages in Silverlight 3
Hi Tim,

I watched you video on navigation which was very easy to follow, and i was able to create a a SL app with navigation and UriMapping, all worked fine.

I wanted to extend this further, so in one of the pages i navigate to, i split the page into a left sub menu and a right content area and created another navigation frame there, so that when a sub menu is clicked the content is displayed in the content area, i set JournalOwnership to =OwnsJournal on it. Whenn i click on a sub menu item nothing happens, even though when i debug i can see that it calls the event handler for sub menu, and it calls navigate with the correct Uri without errors, but nothing else happens ,, detail page is not displayed in the content page ..
So i wondered if this is not even possible (to have more than one navigation frame in a SL application)!
What am i doing wrong?

Cheers
Ali
12/27/2010 12:20 PM | # re: Share DataContext among navigation pages in Silverlight 3
Thank Tim for interesting method,
I am new to Silverlight and would like to use this method, but I have some questions. I would appreciate if you can answer them.
It looks nice when I can bind FrameDataContext to some control on the other page. How the same thing can be done by coding in C#? Let say that I navigate from HomePage to CustomerPage. On the CustomerPage I have customerID TextBlock and I would like to show this ID through C# code in TextBlock. Something like: customerID.Text = person.CustomerID.ToString(); What will be the way to extract person class from this.FrameDatacontext? How the this.FrameDataContext can be available to me in C# (and not through xaml) on CustomerPage?

Thank you
6/4/2011 3:12 AM | # very nice
I have used Visual Studio 2010, its work very good and its feature are also nice. Thanks for this post.

 
Please add 5 and 1 and type the answer here:

All postings/content on this blog are provided "AS IS" with no warranties, and confer no rights. All entries in this blog are my opinion and don't necessarily reflect the opinion of my employer or sponsors. The content on this site is licensed under a Creative Commons Attribution By license.