tags:

views:

666

answers:

2

Hi,

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.

A: 

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?

John Saunders
Yes, the Customer class is the same for all customers. The problem is that the current view model uses an event that tells it that the customer information needs to be updated but is only applicable to the view model that is used as part of the list of customers.
A: 

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:

  1. From your WCF callback handler, raise an event with the EventAggregator passing the new customer information along with the customer ID.
  2. 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.

Anderson Imes