MVVM, Prism and Service Discovery - c#

I'm writing an application (Silverlight and WPF) using the MVVM pattern and the Prism framework. In my application I have a grid that contains a list of customers. Under that, I various views that present customer details. All of the information is fed from a WCF service that provides data from queries as well as callbacks which fire events when the data has been received. The detail information is updated when the selected item in the grid is changed. There is also a filtering view that controls the date range for the detailed information.
I also need to implement a similar set of views, but for a specific customer. The information presented is the same, so obviously it would be best to reuse the same view and model classes.
My initial thought was to build a separate intermediate service that sat between the models and the WCF service for both scenarios. I would then bind the models to the specific service by registering instances by name.
Unfortunately, this would mean that I would have to instantiate a lot of the classes myself instead of relying on dependency injection which I would prefer.
So, for all the MVVM gurus out there, how should the views, models, and services be structured to best use the features of the Prism framework and promote code-reuse?
Many thanks!
==== Edit: added following text and example ====
Here is a simple example that I hope explains what I'm trying to accomplish.
public class CustomerViewModel : ICustomerViewModel
{
public ICustomerView View { get; private set; }
private readonly ICustomerService customerService { get; set; }
private Customer customer;
public CustomerViewModel(ICustomerView view, ICustomerService service, IEventAggregator eventAggregator)
{
customerService = service;
eventAggregator.GetEvent<SelectedCustomerChangedEvent>().Subscribe(CustomerChanged);
eventAggregator.GetEvent<CustomerInfoUpdatedEvent>().Subscribe(CustomerUpdated);
View = view;
View.Model = this;
}
public string Name
{
get
{
return customer.Name;
}
}
public string Email
{
get
{
return customer.Email;
}
}
public void CustomerChanged(int customerId)
{
customerService.RequestCustomerInfo(customerId);
}
public void CustomerUpdated(Customer customer)
{
this.customer = customer;
}
}
This customer view model based on the current design where the customers are in a grid. Selecting a customer fires the SelectedCustomerChangedEvent which will cause the view model to request information.
It is fed from an underlying WCF service that is using a callback mechanism to provide data (the data can take a long time to retrieve / calculate so a simple WCF call won't work). This works just fine. The problem is that I want to reuse this same view and model in a different area of the application that displays information about a specific customer instead of the current selected customer.
My initial thought was to create an intermediate service that handled the SelectedCustomerChangedEvent for the list and a similar event when the customer-specific view is opened. It would then provide data to the model through the same CustomerInfoUpdatedEvent.
The problem is that since I would now have 2 services that implement the same interface, I would need to name them and then have the view model somehow know which one to retrieve from the container.
I know I've probably made a design error. The good news is that I have time to fix it, but I'm not sure how to fix it.

If the Customer class is the same for all customers (including your specific customer), then use a single service, the same views, and the same model.
Can you tell us why this would not work?

Hmm... there is a lot of information here, but I will take a stab at this.
There's really no reason to complicate this as much as you are trying. It feels like you are receiving callback events from your WCF service... am I right? If so, you want to update the UI if the incoming WCF callback pertains to a customer that the user is viewing. I'll work from these assumptions... let me know if I misunderstand.
I think you have almost what you need. I think all you need to do is the following:
From your WCF callback handler, raise an event with the EventAggregator passing the new customer information along with the customer ID.
From any ViewModel's constructor, subscribe to the CustomerUpdated event and add a filter for the customer ID you are looking at in your view model. You are missing this, but it's critical, otherwise you will get a firehose of events that don't pertain necessarily to your instantiated ViewModel. There is a sample of this technique in this quickstart: http://msdn.microsoft.com/en-us/library/dd458918.aspx
Again, this is my best effort at understanding what you are trying to accomplish. Let us know if it's not.

Related

Best approach for calling a web service (or similar) with MvvmCross

I've been giving this some thought lately and I was hoping someone who has better knowledge of MvvmCross than myself can shed some light on this. Given the nuances between each mobile platform there are probably a few different factors that can affect this problem. But for this scenario let's assume we want the best approach for a cross platform solution.
So let's say we have a basic View and a ViewModel class setup. Here's an iOS example.
View
public partial class FirstView : MvxViewController<FirstViewModel>
{
public FirstView(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
Request = new MvxViewModelInstanceRequest(FirstViewModel.NewInstance());
base.ViewDidLoad();
}
}
View Model
public class FirstViewModel : MvxViewModel
{
public static FirstViewModel NewInstance()
{
return Mvx.IocConstruct<FirstViewModel>();
}
public FirstViewModel()
{
}
}
Now at the loading of this View or at some point just before the view is created we want to fetch some data from the web using a service that we inject using dependency injection; because the displaying of the view depends on that data. Here lies the problem.. at which point from a platform perspective and in the MvvmCross lifecycle would be the most appropriate place to call the web fetch function in the service.
With regards to platform I would assume that we should do it once the view loads. Because if the fetched data is anything other than simple data types it will be inconvenient to work with on Android, as one would have to persist the data to disk and retrieve it after the navigation, due to serialization between activities.
So assuming we called the web fetch during the view loading process. Where is the best place in the MvvmCross architecture to fire it off, that most closely follows the design paradigms. e.g. The View Model. Is there any lifecycle methods that someone could recommend to call it inside as well. Something like the Start method, called after the view model has been created.
First of all, I don't understand why you won't let the platform itself instantiate and do it's ViewModel lifecycle instead of creating a new instance of the ViewModel using Mvx.IocConstruct. That method does not invoke the ViewModel lifecycle and will not call neither Init or Start on the ViewModel.
If you let the platform do this for you, first the Init method will be called with the arguments that you set when using ShowViewModel<T>(args).
When ViewDidLoad invokes the Start method will subsequently be called.
This gives you two places to invoke the Service that you inject in the ctor of the ViewModel.
If you want more control over when to download the data, you could create some ICommand's, which you invoke on your ViewModel in any of the ViewController lifecycle methods. This could be in the ViewWillDisappear/ViewDidDisappear method, or you could fetch the data.
There are so many ways you can do this. In the end it is entirely up to you, and you can't possibly know when a user decides to change to another View. However, you can make qualified guesses and try fetch data before the user actually wants it.
There is a nice article for you to read here, by Rob Gibbens on how you could do Resilient network services. It describes how you could speculatively fetch resources based on what the user is doing, and this way have something ready for the user to see when he enters the View. This could be cached data or fresh data that you are fetching after showing the cached version.
In any case, I would suggest you stop loading your ViewModel's with Mvx.IocConstruct and let MvvmCross handle this for you in order to get lifecycle methods invoked.

Proper way to communicate/pass values between viewmodels?

I know there's a lot of questions on the topic and I understand how to do it but I need some help on the design of my architecture. I'm using the Simple MVVM Toolkit.
Architecture
I have a ShellVM which is the main VM for my app. It dishes out navigation and props that my main view binds to.
Then I have a ManageVM that does all the grit work for managing the client, stores, imports, exports etc. It also handles navigation of all my management views.
Then I have an ImportVM that fleshes out the importing of data.
I also have a static PageValues dictionary that stores pages and specific properties and values that should be retained when switching views. It also stores any 'global' properties that is used throughout certain VMs.
I'm using Messaging to pass data between the VMs. The validation and prompts (using dialogs) of the PageValues data is controlled in my ManageVM. I placed it here as I feel my ManageVM should handle all 'management' like setting the client and store. Setting the actual values is done by sending a message to the ShellVM that handles this.
The ShellVM handles the CRUD of the PageValues. So in other words, if any VM gets or sets a global/shell-wide property, it does so by means of messaging to the ShellVM. The ShellVM then sends the message/result back to whichever VM requested it.
Question
This feels very spaghetti-like. I've got a ManageVM that does the loading and validations on PageValues that are actually CRUD'ed in the ShellVM.
Am I on the right track or is there any other suggestion I can try to make this feel a bit cleaner?
Thanks for reading.
Edit
What I'm trying to achieve is to have a container that holds values (ie client and store) that could be accessible from multiple VMs. A bonus is to have each page's/view's values in this container too. Then on showing of the view, it will grab its values from the container and populate the view.
You said
if any VM gets or sets a global/shell-wide property, it does so by
means of messaging to the ShellVM
I propose an interface based approach instead of message passing for this purpose. ViewModels passing messages is for view models to communicate,not for setting a global state. If there is a global state of the application,it is better handled through a dedicated service, IMO.
public interface IApplicationService
{
//your applcation methods here
}
public class ApplicationService:IApplicationService
{
}
public class ManageVM
{
public ManageVM(IApplicationService){}
}
public class ShellVM
{
public ShellVM(IApplicationService){}
}
public class SomeOtherVM
{
public SomeOtherVM(IApplicationService){}
}
Yes, this does sound rather messy. You need to try and isolate areas of functionality into their own VMs so they are not dependent on one another.
One of the tricks I use to do this is to try and imagine that I suddenly need to copy a blob of functionality (say one of your pageviews) into another application. How easy would it be? Would it be a case of just copying one VM and injecting a few dependencies? Or is the VM impossibly coupled to the rest of the app?
It's a bit difficult to give advice without knowing exactly what your app is doing, but really you want each PageVM to be in charge of it's own validation, and CRUD. Or, if the data is shared between many pages, then you need to pass in some kind of repository than the PageVMs can query for data. If validation logic is specific to some data, then put it on the model itself and just leave the presentation of that validation to the VM.
For global settings, I tend to pass around a settings object rather than using messaging.
Have a read up on inversion of control, and dependency injection. These can help you to keep objects loosely coupled because you can see exactly what other things your object is depending upon by looking at the constructor. If you are passing in half the application then it can serve as a warning alarm to try and reduce the coupling.

C# WinForms Model-View-Presenter (Passive View)

I'm developing a WinForms application in C#. I have limited experience in GUI programming, and I am having to learn a great deal on the fly. That being said, here's what I am building.
See the general GUI look at the following link:
GUI http://img227.imageshack.us/img227/1084/program0.jpg
Now, I have done a lot of the work already, but in the very bad Autonomous design pattern. I did not know the project would ever reach a certain size, and, as such, it is time to do some major refactoring.
I have been studying a great deal about GUI design patterns, and the pattern I am wishing to implement is the Passive View (see http://martinfowler.com/eaaDev/PassiveScreen.html). I am looking for some help on how to bring this all together.
Background:
1) Depending on what the user clicks in the "TreeView", the "List" in the bottom left-hand corner will display a list of objects that can populate the "Editor" area. These objects might be a TextBox or a DataGridView. The user toggles the List to choose what he/she wants to see in the "Editor"
2) The model is essentially a folder with data and configuration files. There is an external program that runs on a given directory, creates output files/folders, etc. This program I am developing is designed to effectively manage/configure these objects in a user-friendly way
3) The problem with the way I have been doing things is that it is next to impossible to test, and hence the move to the MVP-esque Passive View design pattern
I am trying to make it so that the program works independently of the View. I have not been able to find any examples where a more complex, interactive view is used with the Passive View pattern.
Questions:
1) Do I need to implement one large interface/view for the entire "look" of the program, then implement sub-interfaces/sub-views for each of the TreeView, Editor, Logger, etc.? Or is there a better "structure" to doing this?
2) When it comes to "handing off" events from the View to the Presenter/Controller (whatever terminology you wish to use W.R.T. the Passive View design pattern), what is the way I should be doing this? Sometimes I have simple properties that need to be updated, and sometimes I need a whole series of steps to unfold.
I would love suggestions and advice on this topic. I have scoured the Internet, and I haven't found adequate examples to help me continue with this project.
Thanks in advance!
Daniel
Here is a simple example that demonstrates the concept of passive views using the MVP design pattern. Because we are using passive views the view has no knowledge of the presenter. The presenter will simply subscribe to events published by the view and act accordingly.
To start out we need to define a contract for our view. This is typically achieved using an interface, essentially, we want to have a very loose coupling with our view. We want the ability to switch to different views or event create mock views for unit testing.
Here is a contract that describes a simple view that will be used to display customer information
public interface ICustomerManagementView
{
void InitializeCustomers(ICustomer[] customers);
void DisplayCustomer(ICustomer customer);
event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
It exposes a single method InitializeCustomers that will be used to initialize our view with objects from our model.
We also have an event SelectedCustomerChanged that will be used by our presenter to receive notification that an action has occurred in the view.
Once we have our contract we can start to handle these interactions in our presenter.
public class CustomerManagementPresenter
{
private ICustomer _selectedCustomer;
private readonly ICustomerManagementView _managementView;
private readonly ICustomerRepository _customerRepository;
public CustomerManagementPresenter(ICustomerManagementView managementView, ICustomerRepository customerRepository)
{
_managementView = managementView;
_managementView.SelectedCustomerChanged += this.SelectedCustomerChanged;
_customerRepository = customerRepository;
_managementView.InitializeCustomers(_customerRepository.FetchCustomers());
}
private void SelectedCustomerChanged(object sender, EventArgs<ICustomer> args)
{
// Perform some logic here to update the view
if(_selectedCustomer != args.Value)
{
_selectedCustomer = args.Value;
_managementView.DisplayCustomer(_selectedCustomer);
}
}
}
In the presenter we can use another design pattern called dependency injection to provide access to our view and any model classes that we may need. In this example I have a CustomerRepository that is responsible for fetching customer details.
In the constructor we have two important lines of code, firstly we have subscribed to the SelectedCustomerChanged event in our view, it is here that we can perform associated actions. Secondly we have called InitilaizeCustomers with data from the repository.
At this point we haven't actually defined a concrete implementation for our view, all we need to do is create an object that implements ICustomerManagementView. For example in a Windows Forms application we can do the following
public partial class CustomerManagementView : Form, ICustomerManagementView
{
public CustomerManagementView()
{
this.InitializeComponents();
}
public void InitializeCustomers(ICustomer[] customers)
{
// Populate the tree view with customer details
}
public void DisplayCustomer(ICustomer customer)
{
// Display the customer...
}
// Event handler that responds to node selection
private void CustomerTreeViewAfterSelect(object sender, TreeViewEventArgs e)
{
var customer = e.Node.Tag as ICustomer;
if(customer != null)
{
this.OnSelectedCustomerChanged(new EventArgs<ICustomer>(customer));
}
}
// Protected method so that we can raise our event
protected virtual void OnSelectedCustomerChanged(EventArgs<ICustomer> args)
{
var eventHandler = this.SelectedCustomerChanged;
if(eventHandler != null)
{
eventHandler.Invoke(this, args);
}
}
// Our view will raise an event each time the selected customer changes
public event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
If we wanted to test our presentation logic we could mock our view and perform some assertions.
EDIT : Included custom event args
public class EventArgs<T> : EventArgs
{
private readonly T _value;
public EventArgs(T value)
{
_value = value;
}
public T Value
{
get { return _value; }
}
}
I would break them down into separate views with their own presents, and use a "controlling" presenter / view to manage message delegation between them all. Not only will this aid testability but it'll keep your controls fulfilling SRP, too.
So in your case you might have an IFormManager which your main window will implement, and then an IFileManager, ILoggerWindow etc. etc.
Although it might be a bit overkill to use, I would suggest that you have a look at Smart Client Software Factory (from the Microsoft Patterns and Practices team) - it's not being actively developed any more, but it has a good implementation of MVP and does this sort of view composition stuff quite well, so might give you some good ideas.

MVVM where to put Data Access Layer?

I am investigating WPF's MVVM design pattern. But am unsure where to put the Data Acess code?
In some examples I have looked at, data access is performed directly in the ViewModel. It seems odd to put something like linq to sql in the ViewModel? Other examples have a seperate project for Data Access, this seems more like it?
Is this there a general approach? I feel like I am missing something here!
Thanks
Here's how I've been organizing my MVVM w/ LINQ projects:
Model - I think of the Model as the state of the system. It provides an interface to the data, and it keeps track of system status. The Model does not know about the ViewModel or View--it just provides a public interface to its data and various events to let the consumers (usually ViewModels) know when the state has changed.
ViewModel - The ViewModel is in charge of organizing or structuring all the data needed by the View, keeping track of the status of the view (such as the currently selected row of a data grid), and responding to actions on the view (such as button pushes). It knows what the view needs, but it doesn't actually know about the view.
View - The View is the actual look and feel of the UI. It contains all the built-in and custom controls, how they arranged, and how they are styled. It knows about the ViewModel, but only for the purpose of binding to its properties.
Gateway - This is the part that directly addresses your question. The Gateway (which is basically my way of saying "DataAccessLayer") is its own separate layer. It contains all the code (including LINQ queries) to CRUD or select, insert, update, and delete data from/to your data source (database, XML file, etc.). It also provides a public interface to the Model, allowing the Model to focus on maintaining system state without having to concern itself with the details (i.e., the queries) needed to update the data source.
DataAccess Classes - In C#, these are very simple classes that model your elemental data objects. When you select something using a LINQ query, you will usually create an IEnumerable<T> or List<T> where T is one of your data objects. An example of a data object would be:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
The big advantage of a design like this is that it really separates your concerns. Everything has a specialized job, and it's (usually) pretty easy to know what kind of thing goes where.
The disadvantage is that it may be overkill for small projects. You end up creating a lot of infrastructure for public interfaces that basically pass a single wish through several layers. So, you might end up with a scenario like this: [user clicks Submit, ViewModel tells Model to AddNewPerson, Model tells Gateway to InsertPerson] instead of a scenario like this [user clicks Submit, ViewModel adds new record to the database directly].
Hope that helps.
I would add another layer, essentially what you want is a data factory. You want to create a set of classes that will CRUD to the database for you and return clean POCO objects to the ViewModel.
A good example to look at would the Nerd Dinner book. It covers MVC not MVVM but the patterns are very similar and the way they access data in that solution would be good starting point.
Hope this helps.
Data access should not be in the view model, as this is supposed to be a view specific (possibly simplified) representation of the domain model.
Use a mapper of some sort to map your view model (the VM in MVVM) to your model (the first M). New objects in your model can be created using the factory pattern. Once created, you can store them in a database using the repository pattern. The repositories would then represent your data access layer. In your repository you could use an O/R mapper like NHibernate or Entity Framework.
EDIT:
I see that GraemeF suggests putting the data access code in the model. This is a NOT a good approach, as this would force you to update your domain model if you were to move from e.g. SQL Server to Oracle or XML files. The domain objects should not have to worry about how they are persisted. The repository pattern isolates the domain from its persistence.
MVVM stands for Model, View, and ViewModel. The piece you are missing is the Model, which is where your data access code lives.
The ViewModel takes the Model and presents it to the View for display, so typically you would have something like this:
class PersonModel : IPerson
{
// data access stuff goes in here
public string Name { get; set; }
}
class PersonViewModel
{
IPerson _person;
public PersonViewModel(IPerson person)
{
_person = person;
}
public Name
{
get { return _person.Name; }
set { _person.Name = value; }
}
}
The PersonView would then bind to the properties of the PersonViewModel rather than directly to the model itself. In many cases you might already have a data access layer that knows nothing about MVVM (and nor should it) but you can still build ViewModels to present it to the view.
Your ViewModel should be a thin layer that just services the view. My rule of thumb: if it has to do with the presentation of the UI, then it belongs in the ViewModel, otherwise it should be in the Model.
The WPF Application Framework (WAF) contains a sample application that shows how the Model-View-ViewModel (MVVM) pattern might be used in combination with the Entity Framework.

WPF Data Binding to external data model

I've recently started develping an application using WPF and I'cant really wrap my mind around following thing:
I have a Domain Model of my application which is simple POCO objects serialized to/from harddisk. Then I have the WPF application and I'd like to bind it to various parts of the model. I need to be able to notify UI of changes to underlying model (eg. implement INotifyPropertyChanged) BUT I want to do that without interfeering with my model (read without modifying current implementation of the model). How can I implement changes notification other than modifying the model?
Reason why I want to do that is that I share the model among multiple projects, only one being WPF, and I don't want to add unncecessary code to the model.
One thing that came to my mind was to create "copy" of the model (with INotifyPropertyChanges and BindingLists etc.) but that seems to be hard to maintainn...
Thanks in advance.
Ondrej
Check this out MVVM
Download its source code see the hierarchy.
Basically you still keep simple POCO objects as your models. Then you create a ViewModel around the model like this:
public class CustomerViewModel : INotifyPropertyChanged
{
readonly Customer _customer;
public CustomerViewModel(Customer customer)
{
_customer = customer;
}
public string FirstName
{
get { return _customer.FirstName; }
set
{
if (value == _customer.FirstName)
return;
_customer.FirstName = value;
OnPropertyChanged("FirstName");
}
}
...
}
I see two possible solutions here:
Use a separate model for WPF screens only (MVVM pattern). This will require maintaining two different models, also be prepare for lots of mapping code.
Use PostSharp to "enhance" your model with all necessary boilerplate code. Here you can find example of automatic INotifyPropertyChanged implementation. Remember that introducing PostSharp to the project is an important decision, so I suggest getting familiar with it first.

Categories

Resources