MVVM Light Multiple Data Contexts - wpf

I am new to MVMM Light toolkit (note, I'm using Light on .NET 3.5). So far I am really starting to like the pattern save for two challenges.
I'd like to have reusable XAML templates for certain types of pages in my application. Think of a movie ticket kiosk. Main content in the center but almost always a button somewhere on the screen to cancel or go back. I'd like to have reusable grid(s) where when I create a new page I basically import that grid layout and don't have to worry about the common bits and can just focus on my part. Doing a little research I feel like <ContentPresenter> might be the way to go here but it's still foreign to me.
Assumign I succeed in my first challenge, I would think the data context for those common items (say a Cancel button) would be somewhere else other than that page's ViewModel to avoid a bunch of duplication of code. Is that best approach to take the individual controls and reference a different view model from the XAML? Something like...
<Button ... DataContext={Binding CommonStuffVM, Source={StaticResource Locator}} />

You can use Templates or DataTemplates to create a reusable template defining how an object should look.
For example,
<DataTemplate DataType="{x:Type local:MovieTicket}">
<!-- Write the XAML for your Movie Ticket -->
</DataTemplate>
You can give your DataTemplate an x:Key to reference it specifically in an ItemTemplate or ContentTemplate, or leave it out so it will be used anytime WPF tries to draw a MovieTicket object
<ItemsControl ItemsSource="{Binding MovieTickets}" />
<ContentControl Content="{Binding SelectedMovieTicket}" />
For your second question, I think this would be a bad idea for individual controls, although its a common practice for complete sections of the program.
When using MVVM, your ViewModels are your application, not your UI.
If your window should display a list of Movies for the user to edit, and allow the user to Save or Cancel their changes, then your ViewModel should contain an ObservableCollection<Movie> and contain an ICommand SaveCommand and ICommand CancelCommand
You really want your View to only reflect your ViewModels, and not have them pulling the data they need from all over the ViewModel hierarchy.
Based on your question, you may be interested in a blog article I have about Navigation with MVVM which uses code very similar to what you're asking about. It shows how to change the UI using implicit DataTemplates, and contains a complete code sample that you can download and look at to get a better idea of the MVVM architecture.

Related

how can I bind Bing Pushpins from multiple models?

I have the requirement in my WP7 application to display pushpins on a bing map from multiple data sources and I am not sure of the best way to do this.
So for example it would be something like this, I receive from a web service a list of people, a list of buildings, a list of POIs etc. I would need to display these individually in their own views but also display them on a map with different images for each type.
I am trying to use a MVVM approach so have a class for a Person, class for a building and so on, each one of these has a location. I then have an ObservableCollection for each of these types and so using data binding it is easy enough to do a View for each of these.
At the moment I only have one ViewModel but my first thought is that I think I should really have one ViewModel per type. So PersonViewModel, BuildingViewModel here? However a Map View would then need to take information from each of these views and I am no sure how you bind a view to multiple ViewModels like this or even if that is sensible.
MapItemsControl also only seems to be able to bind to one thing so how can I bind it to multiple different data sources like this? I thought I could create a simple pushpin class but that would then mean having the data for each type duplicated and I eventually want to be able to click on the pushpins to display the details for the pin so wanted to keep the types separate
Any pointers on a way forward much appreciated
Using a MapItemsControl is as you say, the way to do it. And it's very easy. What you want is a ViewModel with a ObservableCollection for each of your types, as you say you already have.
So I guess your problem is that you don't understand how to use Styles and ItemTemplates.
If what you want, is to have the same style for each of the different types, then simply define a common ItemTemplate that you apply to each MapItemsControl.ItemTemplate. Likewise you can define a custom style that you apply to each Pushpin globally, if what's what you want.
<Grid.Resources>
<DataTemplate x:Name="PushpinItemTemplate">
<maps:Pushpin Location="{Binding Location}" Tap="Pushpin_Tap" Style="{StaticResource PushpinStyle}" />
</DataTemplate>
</Grid.Resources>
...
<maps:Map>
<maps:MapLayer>
<maps:MapItemsControl ItemsSource="{Binding People}" ItemTemplate="{StaticResource PushpinItemTemplate}" />
<maps:MapItemsControl ItemsSource="{Binding Buildings}" ItemTemplate="{StaticResource PushpinItemTemplate}" />
</maps:MapLayer>
</maps:Map>

Using Microsoft (or other) ribbon with large project and MVVM

Our application is a large project with many modules and view. The main window has a ribbon in it, and we are looking for the best way to integrate the ribbon in the application.
I've created a service which modules a views can register to add ribbon items relevant for them, and, in addition, any main view instance can provide its own ribbon items relevant to the that instance. a RibbonItem is a small class which abstract the options of a ribbon item, and mainly have Title, Description, Command, UIType and ChildItems. The service is in charge to rebuild the ribbon when the main view changes.
A colleague of mine thinks this is bad MVVM, as users need to design their ribbon view in C# code and not in XAML, and he also say it would be hard in this way to make a group of items disabled or enabled at once, as each command of these items will need to update its CanExecute separately. Instead, he suggested to have a main Ribbon View and ViewModel files, where each developer that want to add a ribbon button for her module or view would need to add them in the View XAML and add a relevant command in the ViewModel. In addition, VisualStates will be used to determine what items will be displayed or enabled based on changes in the ViewModel (such as view change, or selection change). I really don't like this solution, mainly because all developers will have to put their modules knowledge in once big file.
Note that some items in the ribbon (e.g. Options, Exit) are common to the entire application, while some are relevant to a specific application domain and some are only relevant for a specific view.
Edit: I guess my main question is what is the recommended way to allow multiple development teams integrate on a single ribbon? Should we have a single RibbonView and single RibbonViewModel which will contain all of the possible items in a ribbon, and each team will add its items to these V/VM and also define the logic on when to show them (probably by using visual state)? Or do we allow every view, view-model or module register ribbon items (within their own C# code) against a service, and have the service then render the ribbon as needed when the active view changes with all items registered to that type? Or is there any better way to achieve this integration?
What do you think?
Do you have a better idea or an opinion about how to manage the single ribbon resource which is common to multiple developers?
Thanks,
splintor
I agree with Will's comment, your viewmodel should not care or know how it is being rendered or if the designers ever decide to change how it's rendered.
A ViewModel should only contain all required information for the presentation layer to render it.
So the ViewModel should have all the properties that the Ribbon bar needs bind to in order to function. Then you can use a Resources.xaml or some other strategy to present it.
Taking a shot in the dark I would try something like this for the ViewModels:
public interface IMenuViewModel : INotifyPropertyChanged
{
ICommand Command {get;}
string Title {get;}
string Description {get;}
UIType Type {get;}
IList<IMenuViewModel> ChildItems {get;}
}
I would then probably create an abstract class that provides implements INotifyPropertyChanged with a collection class the implements INotifyCollectionChanged to take care of the plumbing code.
I would then probably do something like this in the Resources.xaml
<DataTemplate DataType="{x:Type vm:IMenuViewModel}">
<StackPanel>
<Button Command="{Binding Command}" Content="{Binding Type}"/>
<ItemsControl ItemsSource="{Binding ChildItems}"/>
</StackPanel>
</DataTemplate>
to provide a default view for your viewmodels
and then all someone has to do to create an entry into your ribbon bar is
1) Implement IMenuViewModel
2) Optionally add another DataTemplate entry into your resources.xaml if they want their widget rendered differently like so:
<DataTemplate DataType="{x:Type vm:FooViewModel}">
<v:FooView />
</DataTemplate>
I hope I didn't dig to deep on how I would implement.
The main point is that a ViewModel should only expose properties required for the view to do it's job(which is rendering the ViewModel), not for the ViewModel to do the job or care how it's done.

Creating instances of resources?

I'm brand spanking new to WPF and am trying to play around with projects to better understand what I'm reading.
My understanding of a resource is that it is the instance, you can't use it like a factory and create instances of it. For example, a XAML-defined rectangle. You can reference it, but you can't have numerous instances of it all over the surface.
In WPF, what would be the way to do that? If I define a Rectangle as a resource with specific properties and wanted to have multiple instances of that within a dynamically-generated grid, how should I be going about it? Or is there a different way I should be trying to do this?
Purely academic exercise with no real-world application.
Actually there's nothing about resources in particular that prevents you from using it multiple times. A perfect example of this is brush resources, style resources, etc. You define them in XAML and the XAML parser creates a single instance of the resources and stores them in the resource dictionary and these brushes, styles, etc can be used as property values many times even though only a single instance of the resource was created.
But having said that, as you noted, you can't really define a Rectangle resource and use it multiple times in the visual tree. This has nothing to do with the fact that it's a resource, but rather it has to do with the fact that a FrameworkElement cannot be a child of more than one parent element.
So what we have instead is called "templates". These tell WPF how to create an element tree but does not actually create the tree until you instantiate the template. Below is an example.
<UserControl>
<ItemsControl ItemsSource="{Binding WholeBunchOfItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Rectangle Fill="Yellow" />
<ContentPresenter Content="{Binding}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
In this example I've bound an ItemsControl to a collection of some sort. For each item in the collection, the ItemsControl will use my DataTemplate to render the item. Within a DataTemplate you can use data binding to access the current item.
I would suggest reading up on MSDN about ControlTemplate, DataTemplate, and Style. These are all important concepts in WPF/Silverlight.
To get multiple instances replicated across a grid or listbox, you need to set the data template to define the UI controls for each row of data, and then databind the grid or listbox to a collection of data that determines how many rows and the individual field values.
Key term for you to research first: data template.

MVVM View-First Approach How Change View

Does anybody have an idea how to change screens (views) in a MVVM View-First-Approach (The view instantiates the ViewModel:
DataContext="{Binding Source={StaticResource VMLocator},
Path=Find[EntranceViewModel]}"
)
For example:
In my MainWindow (Shell) I show a entrance view with a Button "GoToBeach".
<Window>
<DockPanel>
<TextBox DockPanel.Dock="Top" Text="{Binding Title}" />
<view.EntranceView DockPanel.Dock="Top" />
</DockPanel>
</Window>
When the button is clicked I want to get rid of the "EntranceView" and show the "BeachView".
I am really curious if somebody knows a way to keep the View-First Approach and change the screen (view) to the "BeachView".
I know there are several ways to implement it in a ViewModel-First Approach, but that is not the question.
Perhabs I missed something in my mvvm investigation and can't see the wood for the trees... otherwise i am
hoping for a inspiring discussion.
One possibility would be to have all views in the (MainWindow(Shell) and using Triggers for their visibility. But having a lot of different screens (views) all declared in the MainWindow doesnt feel right for me...
This question came up while reading this nice way of using MEF with MVVM I found on John Papas Blog: Simple ViewModel Locator for MVVM: The Patients Have Left the Asylum . But as nice as this marriage of view and viewmodel is, it seems like there is no way to change screens that satisfies me. :)
So in my opinion if you have a lot of screens(views) you better use a ViewModel-First-Approach...
This looks like it might help:
Creating a ViewModel : do it before or after model data is available?
Failing that, how about creating the ViewModel once only at startup, and assigning it to each View window as it's created (rather than creating a new ViewModel each time). Then just close the first View and open up a new View as required, reassigning the single ViewModel instance.
You may want to look at Prism (i.e. the composite application library). Prism facilitates navigation between views via the region manager. This might be overkill for your application and can take a while to get your head around. Prism also allows you to develop using the MVVM pattern as well.
You can find more information about prism and prism navigation in the Prism documentation.

General Design Question about data binding in WPF

I'm starting to use Binding in my WPF project and I'm actually confused about few things on the presentation side (XAML).
So I want to populate a TreeView with a List of Categories. I know how to write the right HierarchicalDataTemplate for my List of Category instances.
<HierarchicalDataTemplate ItemsSource="{Binding Path=ChildrenCategories}" DataType="{x:Type src:Category}">
<TextBlock Text="{Binding Path=Name}"></TextBlock>
</HierarchicalDataTemplate>
But what now I don't know is from where to get the list. I have here 2 solutions :
I got a Library Singleton class
which return me the right
arborescence, then I need to use an
ObjectDataProvider in my xaml which
would call the
Library.Instance.Categories method. (Which means that the controller has to be completely separated from the UI).
I got a Property ListCategories
in my page interactionLogic
(OpenUnit.xaml.cs), and bind the
tree with it.
I'm not sure about the purpose of the xaml.cs files, what are they made for? Is it normally used to store the properties (and act as a controller) or simply to have a back-end for the UI (for example get values from the UI?)?
In case the xaml.cs file is used as a controller, how do I bind my data to it, I've tried many solutions without success,my only success was with the use of static binding.
I would appreciate any comment or recommandation about UI and Logic Binding in WPF, hopefully I will get less confused.
Thanks in advance,
Boris
After reading this great article, I got a little bit less confused :
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
The article is about the Model View ViewController pattern, and how WPF integrates it. So it seems that xaml.cs files should be used as the ViewController here, and should hold the properties.
It actually make sense since it's not a good practice to mix the View and the Data, we want the designers should have a completely independant work to do.
Also for the solution 2) it is possible if you set the data context to the current file.

Resources