简体   繁体   中英

C# MVVM - Model to access ViewModel functions

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?

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, ie 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 (ie changing VoteStatus without incrementing the Score value).

Model --> data and it's associated up-/ downvote information.

ViewModel

--> Implementation of up-/ downvoting.

View

--> triggers the up-/ downvote (eg commands).

Dependencies are chained like this View -> ViewModel-> Model. Thats the pattern.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM