views:

41

answers:

1

Hello,

we mvvm lovers all know Josh Smith mvvm sample and how he has saved the customer in the detail customer view by injecting the repository object into the customerViewModel`s constructor.

But a viewmodel should not know about repositories. Its just a model of a view nothing must being aware of persistence etc...

How can I register my Action delegate SaveDocumentDelegate on the DocumentViewModel if its set in the code-behind? Actually I should subscribe the delegate in my DocumentController but how can I instantiate the DocumentView in my DocumentController and set it as Datacontext not doing that in code-behind. Only thing that came to my mind is using a contentcontrol in the window and bind it to the type of the viewModel and datatemplate it with the Document UserControl like this:

<UserControl.Resources>

        <DataTemplate DataType="{x:Type ViewModel:DocumentViewModel}">
            <View:DocumentDetailView/>
        </DataTemplate>

    </UserControl.Resources>

<ContentControl Content="{Binding MyDocumentViewModel}" />

But I do not want to use a control to solve my architectural problems...

xaml:(view first approach)

public partial class DocumentDetailView : UserControl
    {
        public DocumentDetailView()
        {
            InitializeComponent();

            this.DataContext = new DocumentViewModel(new Document());
        }
    }

DocumentViewModel:

 public class DocumentViewModel : ViewModelBase
    {
        private Document _document;
        private RelayCommand _saveDocumentCommand;
        private Action<Document> SaveDocumentDelegate;

        public DocumentViewModel(Document document)
        {
            _document = document;
        }

        public RelayCommand SaveDocumentCommand
        {
            get { return _saveDocumentCommand ?? (_saveDocumentCommand = new RelayCommand(() => SaveDocument())); }
        }

        private void SaveDocument()
        {
            SaveDocumentDelegate(_document);
        }        

        public int Id
        {
            get { return _document.Id; }
            set
            {
                if (_document.Id == value)
                    return;

                _document.Id = value;
                this.RaisePropertyChanged("Id");
            }
        }

        public string Name
        {
            get { return _document.Name; }
            set
            {
                if (_document.Name == value)
                    return;

                _document.Name = value;
                this.RaisePropertyChanged("Name");
            }
        }

        public string Tags
        {
            get { return _document.Tags; }
            set
            {
                if (_document.Tags == value)
                    return;

                _document.Tags = value;
                this.RaisePropertyChanged("Tags");
            }
        }
    }

UPDATE:

public class DocumentController
    {
        public DocumentController()
        {    
            var win2 = new Window2();
            var doc =  new DocumentViewModel(new DocumentPage());
            doc.AddDocumentDelegate += new Action<Document>(OnAddDocument);
            win2.DataContext = doc;
            wind2.ShowDialog();
        }

        private void OnAddDocument(Document doc)
        {
            _repository.AddDocument(doc);
        }
    }

What do you think about that idea?

+3  A: 

But a viewmodel should not know about repositories. Its just a model of a view nothing must being aware of persistence etc...

The viewmodel connects the model and view together; it is exactly what controls persistence, though it does not handle persistence.

We decouple this from other concern by using services.

One way to avoid adding persistence concerns to the viewmodel is by abstracting those concerns into repository interfaces, so that we can inject it as a dependency. In this way we can delegate persistence work in the viewmodel, usually in response to the user's interaction with the view.

Jay
When I follow your advise I should inject the IRepository into the ViewModels constructor? Thats exactly Josh smith is doing no interface he is just using an object of type Repository not IRepository.
Lisa
I updated the init thread with a sample code, please check Jay!
Lisa
@Lisa You can use the class (implementation) or a base class/interface (abstraction). Using an abstraction allows you to substitute a different implementation, which might be an alternative, an adapter, or a stub/mock for testing. As for your update, this seems only to apply to top-level windows. In my experience, there are often "sub-controls" with viewmodels of their own, but here perhaps you only have a window that handles documents without the need for any other viewmodels.
Jay
so injecting a IDocumentRepository to the DocumentViewModels constructor is ok for you?
Lisa
@Lisa Absolutely.
Jay
hm yes I think you could be right probably you are :P its like MVP pattern the presenter gets the IView injected... thanks! ah there is still one question, the most important one... HOW do I inject the IDocumentRepository when I set the DocumentViewModel to the Datacontext of the UserControl in code-behind?
Lisa