Reputation: 2195
I'm working on a REST API implementation in MVVM for Windows Universal Apps.
It is going fine, but I would like to solve one thing.
I have a Post and a Comment class on Model level, and they have Downvote and Upvote functions. The API calls are implemented in the ViewModel, including the calls that tell the server to do the downvote-upvote.
I would like to have the Models Downvote/Upvote functions to trigger the ViewModel's appropriate calls. Is it possible or am I going around it the wrong direction?
Upvotes: 1
Views: 1392
Reputation: 64180
You're stuck where most programmers who begin with MVVM are stucked. You just look only at MVVM and strictly ignoring everything else.
What you see is: Model
, ViewModel
and View
and you try to put all your business logic into one of these.
But the Model
part is more than POCO Objects with a little bit of logic. Services also belong to the model. This is where you encapsulate all business logic which doesn't belong into a certain model.
You could implement a PostService
class and an CommentService
class, which both implement the UpVote/DownVote functionality and call these services from your ViewModel.
public interface ICommentService
{
void UpVote(Post post, Comment comment);
void DownVote(Post post, Comment comment);
}
public class CommentRestService
{
IRestClient client;
public CommentRestService(IRestClient client)
{
this.client = client;
}
public void UpVote(Post post, Comment comment)
{
var postId = post.Id;
var commentId = comment.Id;
var request = ...; // create your request and send it
var response = request.GetResponse();
// successfully submitted
if(response.Status == 200)
{
comment.VoteStatus = VoteType.Up;
comment.Score += 1;
}
}
public void DownVote(Post post, Comment comment)
{
var postId = post.Id;
var commentId = comment.Id;
var request = ...; // create your request and send it
var response = request.GetResponse();
// successfully submitted
if(response.Status == 200)
{
comment.VoteStatus = VoteType.Down;
comment.Score -= 1;
}
}
}
In your ViewModel you simply pass the service via Dependency Injection or get it via ServiceLocator and then use it's method, rather than calling UpVote
/DownVote
on the model.
// in ViewModel
// get via ServiceLocator or DI
ICommentService commentService = ...;
commentService.UpVote(this.Post, this.SelectedComment);
You could also implement this methods on the Model, to encapsulate the actions into the Comment class, i.e. by making Score
and VoteStatus
"private set;"
public class Comment
{
public string Comment { get; set; }
public Post Post { get; private set; }
public VoteType VoteStatus { get; private set; }
public int Score { get; private set; }
public void UpVote(ICommentService commentService)
{
// for this you'd change your Up/Vote method to return only true/false and not
// change the state of your model. On more complex operation, return an CommentResult
// containing all necessary information to update the comment class
if(commentService.UpVote(this.Post, this))
{
// only update the model, if the service operation was successful
this.Score++;
this.VoteStatus = VoteType.Up;
}
}
}
And call it via
SelectedComment.UpVote(commentService);
Later method is preferred, as you have more control of the Comment
object and the Comment
's state can only be modified via Comment
and it's methods class. This prevents from accidentally changing this value somewhere else in code and receive inconsistent state (i.e. changing VoteStatus without incrementing the Score value).
Upvotes: 2
Reputation: 1
Model
--> data and it's associated up-/ downvote information.
ViewModel
--> Implementation of up-/ downvoting.
View
--> triggers the up-/ downvote (e.g. commands).
Dependencies are chained like this View -> ViewModel-> Model. Thats the pattern.
Upvotes: 0