Silverlight MVVM MEF ViewInjection - silverlight

since my title is buzzword compliant I hope I will get lots of answers to my question or any pointers to the right direction.
OK what I usually do is have a ViewModel which contains a list of ViewModels itself.
public class MasterViewModel
{
public ObservableCollection<DetailViewModel> DetailViewModels { get; set; }
public DetailViewModel Detail { get; set; }
}
<ItemsControl ItemsSource="{Binding DetailViewModels}">
<ItemsControl>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<views:DetailsView />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
With this in mind I will now come to my questions. I read a lot of good things about MEF and also saw the dashboard sample of Glenn Block but this was not helping me enough.
What I want to do is sidbar (like the windows sidebar).
Sidebar = StackPanel
ListItems = Gadget
ButI want it MVVM style
OK I have something like a contract
IGadget
I implemented an custom Export.
[ExportGadget(GadgetType = GadgetTypes.News)]
I have my NewsGadgetView.xaml (which implements IGadget) and imports the NewsGadgetViewModel and also makes itself available as ExportGadget.
so far so good. With this I can create a set of gadgets.
Then I have my SidbarView.xaml which imports a sidebarViewModel.
and now I get lost...
I thought of something like a GadgetFactory which uses PartCreator to create my Gadgets.
but this would sit in my SidebarView.xaml
But I want to have control over my Gadgets to add and remove them from my sidebar.
So I thought about something like an ObserveableCollection...
Which I bind to
The GadgetHost is basicaly Grid which will dynamicaly load the Gadget....
So how would I create my sidebar containing different gadgets without knowing which Gadgets are available and have a ViewModel for the sidebar as well as for each gadget?...
Thanks for any help....

This is where the power of the Managed Extensibility Framework comes in. I basically have the same challenge with an existing project.
My resolution was to abstract the views and regions, and then use a routing mechanism.
Basically, there is a custom export for a region, and I export a FrameworkElement (might be a StackPanel, Grid, etc etc), The views have a set of attributes, those are exported as UserControl.
A manager handles the imports using a lazy import collection. It simply assigns these to a dictionary so we have view enums mapping to instances of views, then region enums mapping to instances of the regions.
The route table then waits for a request to activate a view (this may happen on load), and finds the route from the view to the region, then inserts it.
What about the view model?
For "global" information I'm using a contract that is exported, like this:
[Export(typeof(IMasterViewModel))]
public class MasterViewModel
{
}
That has something every plugin may need. Then I have a base view model the "child" view models inherit from:
public class BaseViewModel
{
[Import(typeof(IMasterViewModel))]
public MasterViewModel MasterVM { get; set; }
}
So now let's say I have a completely separate XAP. I will need to reference some "common" interfaces. So I'm not referencing an instance of the global view model, just the contract. However, within my plugin XAP, I can do this:
[Export]
public class PluginViewModel : BaseViewModel
{
etc ... etc ..
}
public partial class PluginControl : UserControl
{
[Import]
public PluginViewModel
{
get { return LayoutRoot.DataContext as PluginViewModel; }
set { LayoutRoot.DataContext = value;
}
}
When the view model is imported to the view, it will also import the master view model, providing access to those other parts. If you need to trigger some action when the view model is available, simply implement IPartImportsSatisfiedNotification and you can fire when ready.

Related

Bind Model with the ViewModel in WPF Prism

Assume I create a bunch of Model classes dynamically (say based on some config file content on startup), say each model is an instance of a class CarModel:
public class CarModel
{
public string CarName { get; private set; }
public CarModel(string carName)
{
CarName = carName;
}
}
All of them then added to ObservableCollection CarList, and then represented in the view in XAML:
<Window.Resources>
<DataTemplate DataType="{x:Type models:CarModel}">
<views:CarView></views:CarView>
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource="{Binding CarList}">
</ListBox>
I then bind CarView to CarViewModel through the Prism AutoWireViewModel.
I use CarViewModel because I have bunch of extra (only view related) properties, and also handle navigation and events (through eventAggregator) that I don't want to include in my original CarModel.
My problem is, how do I bind (or link) my CarViewModel with the original CarModel that created the view?
how do I bind (or link) my CarViewModel with the original CarModel that created the view?
Either by navigating to the view and passing the respective model in the navigation parameters or (preferredly) by creating the view model yourself (through a factory) instead of using the view model locator and initializing it with its model.
That is, CarList should be contain CarViewModels. If you need full two-way synchronization (the list is changed by the database and the view simultaneously), this means a lot of boilerplate code, but most of the time, you need no synchronization at all... so a IReadOnlyColletion<CarViewModel suffices (instead of a full-blown ObservableCollection) and it can be initialized once with a simple Select.
Hint: the view model locator is meant for top-level views mainly, most of the time you're better off creating the view model and linking it to the view with a DataTemplate, i.e. going view model-first. In fact, earlier version of prism supported this approach even when navigating regions, and dropping that made regions far less widely usable sensibly.

What approach should I use when creating a custom WPF control?

I'm about to redo an old WinForms application as a WPF application. The core of this applicaton is a custom "grid" component. I'd like some ideas on the best way to do this as a WPF component.
The application displays a grid of data for different countries/sectors. Each cell of the grid displays different information (e.g. graph, image) depending on the available data for that country/sector.
I have a domain model assembly that I want to keep clean - to maximize reuse. The structure is as follows:
Table
Continents
Countries
Sectors
Data[country, sector]
The grid displays countries down the left and sectors across the top.
In the current application, the grid component has a (POCO) Table property and an Refresh() methods to manually redraw it. So, if the Table is updated, the parent of the grid component refreshes it. The grid component also has a number of events that are fired if a continent, country or cell is clicked - so that the parent can response with pop-up menus, etc.
This all works fine.
However, I'm wondering whether this is the correct model to use for a WPF application. Looking at many of the WPF example, they support data-binding, etc. But, it's not clear, from the simple examples, how I might bind a complex object to my components - or whether it would even be worthwhile.
Also, the WinForms component is completely custom drawn - there are no sub-controls (e.g. Labels) in use. Would it be better to use a WPF user control and build the table from a GridLayout and lots of Label, Shape, etc controls? In practice, they are maybe 20 rows and 20 columns in the grid, and the user regular removes and adds countries/sectors (rows/columnms) while using the application.
My immediate goal is to make sure my design plays well in the WPF eco-system, but I have a secondary goal of learning how to do things in a WPFy way - given this is my first WPF app. I'm pretty on top of the use of building a general WPF app - it's just the custom control stuff that remains a little fuzzy (even after reading around it a little).
Any insights/guidance would be appreciated.
You definitely want to adapt the MVVM approach, as outlined by Josh Smith. Practically, this means that your custom grid component will be contained in it's own View. Backing the view will be your ViewModel, where you will define an ObservableCollection of objects containing your data. These objects will probably come from your Model. This interaction is shown below:
Models:
public class TableData
{
public string Country { get; set; }
public string Continent { get; set; }
public object Sector { get; set; }
}
public class TableManager : ITableManager
{
public Collection<TableData> Rows;
public void GetData()
{
this.Rows = new Collection<TableData>();
this.Rows.Add(...
}
}
ViewModel:
public class TableViewModel
{
private ITableManager _tableManager;
public TableViewModel() : base(new TableManager())
{
}
// for dependency injection (recommended)
public TableViewModel(ITableManager tableManager)
{
_tableManager = tableManager;
_tableManager.GetData();
}
public ObservableCollection<TableData> Rows
{
get { return _tableManager.Rows; }
}
}
View:
<ctrls:CustomDataGrid
ItemsSource={Binding Rows}
AutoGenerateColumns=True
>
<!-- Use AutoGenerateColumns if the # of sectors is dynamic -->
<!-- Otherwise, define columns manually, like so: -->
<DataGridTextColumn
Width="*"
Header="SectorA"
Binding="{Binding Country}
/>
</ctrls:CustomDataGrid>
I used CustomDataGrid in the view because I assume you're going to subclass your own DataGrid. This will allow you to override events to customize the DataGrid to your liking:
public class CustomDataGrid : DataGrid
{
public override Event...
}

Nested Data Context with Unity

I took a course on VB.Net + WPF at university last year. For the final project, I decided to give MVVM a go (we hadn't discussed it at all in the course, I had just researched it and thought it would be a useful exercise). It was a good experience however I'm rather sure I might have made some poor choices when it came to design.
I've since graduated and my job has nothing to do with WPF or Windows development however I'm developing a small application in my own time and thought it would be fun to use C# and WPF (C# is a language I very much like to work with and I enjoyed working with WPF so it's a pretty logical choice).
Anyway, I'm using this as an opportunity to learn more about MVVM and try and implement it in a better way than I did previously. I've done a bit more reading and am finding it a lot easier to graph than I had when trying to implement it alongside learning WPF.
I've used In The Box MVVM Training as a guide and will be using Unity for dependency injection at this.
Now, in the sample app developed in the guide, there is a single view model (MainWindowViewModel). The MainWindow is pretty much a container with 3 or 4 UserControls which all share the DataContext of the MainWindow.
In my app, I'd like to have a tab-based interface. As such, the MainWindow will be primary concerned with displaying a list of buttons to switch the current view (i.e. move from the 'add' view to the 'list view'). Each view will be a self-contained UserControl which will implement it's own DataContext.
The same code in the app is as follows:
MainWindow window = container.Resolve<MainWindow>();
window.DataContext = container.Resolve<MainWindowViewModel>();
window.Show();
That's fine for setting data context of the MainWindow, however how will I handle assigning each user context it's own ViewModel as a DataContext?
EDIT: To be more specific, when I say tab-based interface, I don't mean it in the sense of tabs in a text editor or web browser. Rather, each 'tab' is a different screen of the application - there is only a single active screen at a time.
Also, while Slauma's post was somewhat helpful, it didn't really explain how I'd go about injecting dependencies to those tabs. If the NewStatementView, for example, was required to output it's data, how would I inject an instance of a class that implements the 'IStatementWriter' interface?
EDIT: To simplify my question, I'm basically trying to figure out how to inject a dependency to a class without passing every dependency through the constructor. As a contrived example:
Class A has Class B.
Class B takes as a constructor paramater needs an implementation of Interface I1.
Class B uses Class C.
Class C takes as a constructor paramater needs an implementation of Interface I2.
How would I handle this scenario using DI (and Unity)? What I don't want to do is:
public class A(I1 i1, I2 i2) { .... }
I could register everything using Unity (i.e. create I2, then C, then I1 and B, and then finally insert these into A) but then I would have to instantiate everything when I want to use A even if I might not even need an instance of B (and what if I had a whole bunch of other classes in the same situation as B?).
MVVM has lots of benefits, but in my experience wiring up the view models and the views is one of the biggest complexities.
There are two main ways to do this:
1:
Wire the view models to the views.
In this scenario, the XAML for the MainWindow contains the child controls. In your case, some of these views would probably be hidden (because you are only showing one screen at a time).
The view models get wired to the views, usually in one of two ways:
In the code behind, after the InitializeComponents() call or in a this.Loaded event handler, let this.DataContext = container.Resolve<MyViewModelType>();
Note that in this case the container needs to be globally available. This is typical in applications that use Unity. You asked how children would resolve interfaces like IStatementWriter. If the container is global, the child view models could simply call container.Resolve<IStatementWriter>();
Another way to wire the view models into the views is to create an instance of the view model in XAML like this:
<UserControl ...>
<UserControl.DataContext>
<local:MyViewModelType/>
</UserControl.DataContext>
...
</UserControl>
This method is not compatible with Unity. There are a few MVVM frameworks that allow you to resolve types in XAML (I believe Caliburn does). These frameworks accomplish this through markup extensions.
2:
Wire the view up to the view model.
This is usually my preferred method, although it makes the XAML tree more complicated. This method works very well when you need to perform navigation in the main view model.
Create the child view model objects in the main view model.
public class MainViewModel
{
public MyViewModelType Model1 { get; private set; }
public ViewModelType2 Model2 { get; private set; }
public ViewModelType3 Model3 { get; private set; }
public MainViewModel()
{
// This allows us to use Unity to resolve the view models!
// We can use a global container or pass it into the constructor of the main view model
// The dependencies for the child view models could then be resolved in their
// constructors if you don't want to make the container global.
Model1 = container.Resolve<MyViewModelType>();
Model2 = container.Resolve<ViewModelType2>();
Model3 = container.Resolve<ViewModelType3>();
CurrentViewModel = Model1;
}
// You will need to fire property changed notifications here!
public object CurrentViewModel { get; set; }
}
In the main view, create one or more content controls and set the content(s) to the view models that you want to display.
<Window ...>
...
<ContentControl Content="{Binding CurrentViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:MyViewModelType}">
<local:MyViewType/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelType2}">
<local:ViewType2/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelType3}">
<local:ViewType3/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
...
</Window>
Notice that we tie the child views to the view models through data templates on the ContentControl. These data templates could have been defined at the Window level or even the Application level, but I like to put them in context so that it's easier to see how the views are getting tied to the view models. If we only had one type of view model for each ContentControl, we could have used the ContentTemplate property instead of using resources.
EDIT: In this method, the view models can be resolved using dependency injection, but the views are resolved through WPF's resource resolution mechanism. This is how it works:
When the content for a ContentPresenter (an underlying component in the ContentControl) is set to an object that is NOT a visual (not derived from the Visual class), WPF looks for a data template to display the object. First it uses any explicit data templates set on the host control (like the ContentTemplate property on the ContentControl). Next it searches up the logical tree, examining the resources of each item in the tree for a DataTemplate with the resource key {x:Type local:OBJECT_TYPE}, where OBJECT_TYPE is the data type of the content. Note that in this case, it finds the data templates that we defined locally. When a style, control template, or data template is defined with a target type but not a named key, the type becomes the key. The Window and Application are in the logical tree, so resources/templates defined here would also be found and resolved if they were not located in the resources of the host control.
One final comment. If a data template is not found, WPF calls ToString() on the content object and uses the result as the visual content. If ToString() is not overridden in some meaningful way, the result is a TextBlock containing the content type.
<--
When you update the CurrentViewModel property on the MainViewModel, the content and view in the main view will change automatically as long as you fire the property changed notification on the main view model.
Let me know if I missed something or you need more info.
For a Tab-based interface this classical article about MVVM pattern in WPF might be very useful. (It also offers a downloadable sample application.)
The basic idea to connect each tab with a UserControl is as follows (only a rough sketch, details are in the article):
The MainWindow View has a ContentControl ...
<ContentControl Content="{Binding Path=Workspaces}"
ContentTemplate="{StaticResource WorkspacesTemplate}" />
... which binds to a collection of "Workspaces" in the MainWindowViewModel:
public ObservableCollection<WorkspaceViewModel> Workspaces { get; private set; }
This WorkspaceViewModel serves as a base class for all ViewModels you want to display as a tab.
The WorkspacesTemplate is a DataTemplate which binds a TabControl to the collection of WorkspaceViewModels:
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}" />
</TabControl>
</DataTemplate>
And for every specific Tab you have a UserControl with a ViewModel which derives from WorkspaceViewModel ...
public class MySpecialViewModel : WorkspaceViewModel
... and which is related to the UserControl by a DataTemplate:
<DataTemplate DataType="{x:Type vm:MySpecialViewModel}" >
<v:MySpecialUserControl />
</DataTemplate>
Now, if you want to open a tab you would have a Command in the MainWindowViewModel which creates the ViewModel belonging to that tab and add it to the Workspaces collection of the MainWindowViewModel:
void CreateMySpecialViewModel()
{
MySpecialViewModel workspace = new MySpecialViewModel();
Workspaces.Add(workspace);
}
The rest is done by the WPF binding engine. The TabControl recognizes automatically that this special workspace item in the collection is of type MySpecialViewModel and selects the right View/UserControl through the DataTemplate we have defined to connect ViewModel and View and displays it in a new Tab.
At the point where you resolve your Views deriving from UserControl, use property injection to resolve a new ViewModel for each one and set the DataContext property of the view to it.

How to reuse entity framework datasource for multiple views WPF EF MVVM

Hi I am designing an application using WPF4, EF and MVVM. I want to be able to create reusable UserControls that I can use in multiple windows in the application, and have them draw data from the same source.
Lets say I have a GraphView component and a TableView component that can appear on the same page or in different places in the application, and I want them to both reflect the same collection of filtered EF entities. MVVM common practice seems to require that each view has its own viewmodel. But should I be be using a joint viewmodel and bind both to it, so if you change the data or filter, both would update simultaneously? If not how should I handle this?
Thanks for any advice!
One approach could be to have two ViewModels, one for each of your Views/UserControls, and then nest them into some top or higher level ViewModel. If, for example, both Views reside in a MainWindow View, it could look like this:
public class MainWindowViewModel
{
public MainWindowViewModel(IRepository repository)
{
SharedUserControlData sharedData = new SharedUserControlData()
{
MyCollection = new ObservableCollection<MyEntity>(
repository.GetMyEntities()),
// instantiate other shared data properties
}
UserControl1ViewModel = new UserControl1ViewModel(sharedData);
UserControl2ViewModel = new UserControl2ViewModel(sharedData);
}
public UserControl1ViewModel UserControl1ViewModel { get; private set; }
public UserControl2ViewModel UserControl2ViewModel { get; private set; }
// more stuff...
}
You have a SharedUserControlData class which contains properties both views can bind to:
public class SharedUserControlData : INotifyPropertyChanged
{
public ObservableCollection<MyEntity> MyCollection { get; set; }
// other properties
// INotifyPropertyChanged implementation
}
And the ViewModels of the UserControls get those data injected:
public class UserControl1ViewModel
{
public UserControl1ViewModel(SharedUserControlData data)
{
SharedUserControlData = data;
}
public SharedUserControlData SharedUserControlData { get; private set; }
// more stuff
}
// and the same for UserControl2ViewModel
Your UserControl Views are bound to the ViewModels by a DataTemplate:
<DataTemplate DataType="{x:Type vm:UserControl1ViewModel}" >
<v:UserControl1View />
</DataTemplate>
// and the same for UserControl2ViewModel
And some controls inside of the UserControls are bound then to SharedUserControlData.MyCollection and other properties of the UserControlViewModels. The DataContext of the MainWindow is the MainWindowViewModel:
IRepository repository = new MyRepository(); // or use Dependency Injection
MainWindow window = new MainWindow();
MainWindowViewModel viewModel = new MainWindowViewModel(repository);
window.DataContext = viewModel;
In the XAML of your MainWindow we bind the UserControls to the nested ViewModels of the MainWindow's DataContext (which is the MainWindowViewModel):
<StackPanel>
<v:UserControl1View DataContext="{Binding UserControl1ViewModel}" />
<v:UserControl2View DataContext="{Binding UserControl2ViewModel}" />
</StackPanel>
This way both UserControls would have different ViewModels but both share the same SharedData instance which comes from the higher level ViewModel containing both UserControl's ViewModels. The Repository then has access to the EF data context. (Having repositories here is only an example, you could also inject instances of Service classes or something.)
Your EF classes, near as I've been able to tell after only four days using EF, reside at the project level. My first instinct would be to implement a singleton containing references to the entities you want to hold common across your viewmodels. That will create a class dependency on your singleton, of course.
This actually sounds like a design problem addressed by Unity, MEF, or something else that will do dependency injection. You'd have your EF classes in a module of one of those frameworks and use their protocols to coordinate between EF and your VM's. Then a change in your filter or your data in EF would also trigger a message your VM's could register to receive, in order to trigger UI changes or VM state changes or whatever.
I agree wholeheartedly with the one ViewModel per View approach. For shared data you can either pass references around (tedious and error prone), you can use DI (depending on your comfort level but doesn't play well with design time data), or you can create static properties in your App.xaml.cs which are then shared and accessible throughout the application. In the long run, DI will probably get the most support from other folks.
You might have a look at the BookLibrary sample application of the WPF Application Framework (WAF). It contains two different Views (BookListView [Master], BookView [Detail]) for the same data source which is provided by the Entity Framework.

MVVM: Giving every modular part it's own XAML class

I was thinking about doing this instead defining lot's of DataTemplates. This would mean that if I had a collection of things the ItemsControl itself would have a XAML class and the objects would have one too.
This is something that already happens when the objects are proper ViewModels containing models and logic but if it's just a Command for example. A dynamic group of commands perhaps.
Pros: I could use the designer to help me define the look of the object as I don't have blend and it would be easier to find and change those parts if needed.
Cons: More XAML classes.
Would you talk me into this or out of this.
EXAMPLE
I have buttons all around the app so I define a ButtonViewModel which has a display name and a ICommand Property. I would also define a DataTemplate or UserControl for this object which would basically be a button with Command binding and text/content binding to the display name. I could also define it's look and such.
Then in ViewModels that should include buttons I would add these buttons as part of the class and bind to them inside the view.
public class ButtonViewModel : ViewModelBase
{
private string _displayName;
public string DisplayName
{
get
{
return _displayName;
}
set
{
_displayName = value;
RaisePropertyChanged("DisplayName");
}
}
private ICommand _command;
public ICommand command
{
get
{
return _command;
}
protected set
{
_command = value;
RaisePropertyChanged("Command");
}
}
public ButtonViewModel(ICommand command, string displayName)
{
Command = command;
DisplayName = displayName;
}
}
ViewModel using the ButtonViewModel
public class SomeViewModel : ViewModelBase
{
//some functionality
//It could be done as a collection or just seperate ButtonViewModel properties
public ObservableCollection<ButtonViewModel> Buttons { get; set; }
//Somewhere where it makes sense, here in the constructer for the heck of it
public SomeViewModel()
{
Buttons.Add(new ButtonViewModel(new RelayCommand(Save, canSave), "Save"));
Buttons.Add(new ButtonViewModel(new RelayCommand(Edit, canEdit), "Edit"));
Buttons.Add(new ButtonViewModel(new RelayCommand(New, canAddNew), "New"));
}
}
The buttons view:
<UserControl x:Class="WpfApplication1.ButtonView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="60" Width="90">
<Button Command="{Binding Path=Command}" Content="{Binding Path=DisplayName}">
<!-- Some really cool design for your button -->
</Button>
</UserControl>
You could also define a specific ItemsControl to hold a collection of buttons, even going so far as to define a ViewModel for said itemscontrol.
I once learned that if you can encapsulate some item in a class you should. Is this just crazy talk?
I'm not quite sure what you're asking, but it sounds as if you are taking a view first approach, which can get very complex in everything but the simplest of apps. Have you considered using an MVVM framework such as Caliburn.Micro?
Using a view model first approach, you can instantiate your view model, and then use Caliburn.Micro to locate your view (via convention), and automatically bind the two up.
Caliburn.Micro will also do view composition, so for example, if you have a collection of view models on your parent view model, and you expose that collection from a property with the same name as a ListBox on your view, then Caliburn.Micro will automatically use the corresponding view for each item in the collection, and bind up each items view model with the view.
You can also use different views over the same view model, and Actions are used to invoke verbs on your view models from view controls, rather than commanding, which allows for much richer imagining of UIs.

Resources