a.toraby
a.toraby

Reputation: 3391

Are there any reasons to use a generic View Model though we can not apply them in xaml?

According to this question and the very useful answers from nice guys, I found there is no support for generic types in XAML. We are not allowed to instantiate a generic view model for our user controls. But, according to this fact I decided to bring up another questions:

  1. Why should we create a generic view model when we can not use it in a view? we have to define concrete classes for each type so what's the benefit of having a generic class at all? At first I tried generic View Model because I thought it would be possible to customize Views according to the typed arguments. And work with content of the WPF components with typed methods.
  2. People suggest me to create a base generic view model and several child concrete classes for each Type. In this scenario what could be usage of that generic class? As far as I know a View Model is a concept that is useful for binding to a Data context. So if there is no means to access those typed arguments in the DataContext why should I use a generic View Model, Since there is no other usage for a View Model? because all of the logic and business of the application is in the center of the Model. And View Model only prepares presentation of the data inside Model for View.
  3. Why Microsoft did not provide this functionality in XAML? Is there any restriction for developing such a feature in WPF? Or something like this, is actually a logical contradiction with the nature of the MVVM?

Upvotes: 1

Views: 1518

Answers (1)

LueTm
LueTm

Reputation: 2380

I can understand your frustration, but I think there is a misunderstanding with the MVVM pattern here:

  1. A generic base class would be useful if you have a lot of shared functionality between your view models. However, in MVVM, ViewModels are meant to be more complicated (and different) than in MVC. They talk to services and function as the glue between the GUI and the lower layers/code/business logic, or whatever. You actually could use a generic view model using DI/IoC, by just injecting a ViewModelBase and set is as the data context, preferably in the constructor. Depending on the IoC container you use, you would just need to register your type with it. However, it is very suspicious that all the code for the view model you need is in that base class - meaning that there is no code specific to a certain view model! I suspect that you mistake the MVVM view model with the MVC view model, which is a common mistake I've seen.

  2. This is the part where I think you misunderstand the ViewModel in the MVVM pattern.

because all of the logic and business of the application is in the center of the Model. And View Model only prepares presentation of the data inside Model for View.

  1. (continued) It does those things, but it also handles calls back from the view into the business logic and the model (RelayCommands, DataBindings that are TwoWay). And it also loads in the data when the view is created. So don't mistake the view model in MVVM to be just a converter from ModelClass to ModelClassForViewBinding.

  2. There probably are some tricks you could apply to make this work. However, most of us never come across this problem. My guess is that it would require too much change in the markup and additional functionality for very few yield. It is not a contradiction with MVVM, because of the reasons explained above.

The shortest way I can describe the view model is that it is more similar to the Presenter in the MVP pattern. It is the DataContext of the element root. It orchestrates the loading of all the required data. It handles calls from the view from buttons clicks, text changed, lost focus etc via RelayCommands and converts them to method calls into the business logic over services and repositories. A simple read only view model could look like this:

[ImplementPropertyChanged]
public class CustomerViewModel : ViewModelBase<Customer>
{
    public bool IsBusy { get; private set; }

    private ICustomerRepository _customerRepository;
    private IWindowService _windowService;

    [Inject]
    public CustomerViewModel(ICustomerRepository customerRepository, IWindowService windowService)
    {
        _customerRepository = customerRepository;
        _windowService = windowService;
        LoadData();
    }

    private async void LoadData()
    {
        IsBusy = true;

        try 
        {
            // Customer would be in your base, as public T BusinessObject { get; protected set; }
            BusinessObject = await _customerRepository.GetSelectedCustomer();
        }
        catch (Exception err)
        {
            _windowService.ShowErrorWindow(err);
        }
        finally
        {
            IsBusy = false;
        }
    }
}

This would be the data context of the visual root (UserControl or similar). There is no way all that logic applies to a ViewModelBase or similar. So this is why I suspect a misunderstanding of the pattern.

Hope this helps.

Upvotes: 1

Related Questions