Thursday, May 17, 2012    
Blog  

OpenLight Blog

Deleting A Silverlight DataGrid Row With A Button On The Row

Aug 7

Written by:
8/7/2010 10:50 PM  RssIcon

NOTE: If you feel that this is way too complicated, you can use the method described here: "A Simple DataGrid Delete Button Using View Model / MVVM". The difference is that you would not have a Delete Button on each row.

image

Download the code: [at this link]

The topic of this blog may not seem like such a big deal unless you tried to do it. I demonstrated a method to raise an ICommand in the tutorial “Using The Silverlight DataGrid with View Model”, however what that does is insatiates a second copy of the main View Model.

You can call the ICommand, (for example to delete a record), and it will work. the problem is, that if you want to then remove the record from the DataGrid, you will discover that you can’t, because the View Model that you instantiated, is not connected to the .xaml page that the UI is on.

Dan Wahlin covers this in detail, if you’re still confused on what the problem is. He also has a solution that may also work for you.

The Problem

  • We need to call a ICommand in a DataGrid, to delete an RIAComment.
  • We need to remove the RIAComent from the collection the DataGrid is bound to (so it disappears).

The Solution

  • We “wrap” the collection of RIAComments into a Wrapper Class.
  • In the Wrapper Class, we add an ICommand to delete the RIAComment, and also add the code to call the web service, to actually perform the deletion.
  • We create a Property in the Wrapper Class, to store an instance of the main View Model, so we can update the collection the DataGrid is bound to (and make the comment disappear).

The Details

image

First we make a class called RIACommentsCollectionWrapper. Basically it’s exactly like a normal View Model. The only difference is that we have these properties:

  • objMainPageModel – This property will hold an instance of our main View Model and allow us to communicate with it.
  • DeleteRIAComment – This is a normal ICommand that will be called by the Delete button. All the code to actually call the web service and delete the RIAComment is also in this class.
  • objRIAComment – This is the actual RIAComment object that would normally be in a collection bound to the DataGrid.

image

We update the Web Service to add a DeleteRIAComment method:

    #region DeleteRIAComment
    [WebMethod]
    public RIAComment DeleteRIAComment(int RIACommentID)
    {
        RIATasksDBDataContext DB = new RIATasksDBDataContext();
 
        RIAComment ReturnRIAComment = new RIAComment();
        ReturnRIAComment.CommentID = RIACommentID;
 
        var result = (from RIAComments in DB.RIAComments
                        where RIAComments.CommentID == RIACommentID
                        select RIAComments).FirstOrDefault();
 
        DB.RIAComments.DeleteOnSubmit(result);
        DB.SubmitChanges();
 
        return ReturnRIAComment;
    }
    #endregion

(note, sorting will work, but it was taken out of the original code example to reduce the code complexity)

 

 

Wrapping the RIAComments in the Wrapper Class

In the main View Model, we alter the RIACommments collection to use the Wrapper Class, (RIACommentsCollectionWrapper), instead of just RIAComments:

    #region colRIAComments
    private ObservableCollection _colRIAComments
        = new ObservableCollection();
    public ObservableCollection colRIAComments
    {
        get { return _colRIAComments; }
        private set
        {
            if (colRIAComments == value)
            {
                return;
            }
            _colRIAComments = value;
            this.NotifyPropertyChanged("colRIAComments");
        }
    }
    #endregion

 

When we retrieve the RIAComments from the web service, we wrap them in the Wrapper Class:

 

    // loop thru each item
    foreach (var RIAComment in EventArgs.Result)
    {
        // Make a instance ofthe Wrapper
        RIACommentsCollectionWrapper Wrapper = new RIACommentsCollectionWrapper();
        // Add the RIAComment to the Wrapper
        Wrapper.objRIAComment = RIAComment;
        // Add an instance of this Main ViewModel to the Wrapper
        Wrapper.objMainPageModel = this;
 
        // Add the Wrapper to the collection that the DataGrid will be bound to
        colRIAComments.Add(Wrapper);
    }

 

All code that needs to reefer to the RIAComments collection, now needs to go through the Wrapper Class:

 

    #region GetRIACommentCommand
    public ICommand GetRIACommentCommand { get; set; }
    public void GetRIAComment(object param)
    {
        GetRIAComment((param as RIACommentsCollectionWrapper).objRIAComment);
    }
 
    private bool CanGetRIAComment(object param)
    {
        return true;
    }
    #endregion

 

The View – Expression Blend

image

In Expression Blend, we are able  to create sample data and bind to the RIAComments.

image

The only difference, is that we have to navigate through the Wrapper Class, to bind to the properties we want.

image

When we edit the column that the Button is on, in the DataGrid

image

… and select it…

image

We click the New button next to it’s DataContext.

image

We set it’s DataContext to the Wrapper Class, (RIACommentsCollectionWrapper).

Note that this means we are creating a second copy of the Wrapper Class. We would not be able to update the main View Model if we did not have the “objMainPageModel” property.

image

Now when we drop a InvokeCommandAction Behavior on the button, we will be able to call the ICommand in the Wrapper Class that will delete the RIAComment.

 

Deleting The RIAComment From The DataGrid

In the Wrapper Class, this is the code that calls the Web Service to delete the RIAComment, and to remove it from the collection on the main View Model so it disappears on the DataGrid.

Note that where you see “objMainPageModel”, the code to calling the main View Model:

#region DeleteRIAComment
private void DeleteRIAComment(int CommentID)
{
    // Call the Model to UpdateRIAComment the RIAComment
    RIACommentsModel.DeleteRIAComment(CommentID, (Sender, EventArgs) =>
    {
        if (EventArgs.Error == null)
        {
            // Find the comment 
            var CommentInCollection = 
                (from comment in objRIACommentsCollectionWrapper.objMainPageModel.colRIAComments
                                        where comment.objRIAComment.CommentID == EventArgs.Result.CommentID
                                        select comment).FirstOrDefault();
 
            if (CommentInCollection != null)
            {
                // Remove it
                objRIACommentsCollectionWrapper.objMainPageModel.colRIAComments.Remove(CommentInCollection);
            }
 
            // Show any errors
            objRIACommentsCollectionWrapper.objMainPageModel.Errors = 
                EventArgs.Result.Errors;
 
            // Set the visibility of the Message ListBox
            MessageVisibility = (objRIACommentsCollectionWrapper.objMainPageModel.Errors.Count > 0) ? 
                Visibility.Visible : Visibility.Collapsed;
        }
    });
}
#endregion

In Summary

When we set the DatContext of the Delete Button, we are creating a second instance of the Wrapper Class.

The only reason we are able to delete the RIAComment from the collection that is bound to the DataGrid, is that we have a Property in that class, (objMainPageModel), that stores an instance of the main View Model.

3 comment(s) so far...


Gravatar

Re: Deleting A Silverlight DataGrid Row With A Button On The Row

Note, I explain more about this code in this forum thread:
forums.silverlight.net/forums/p/194515/453706.aspx#453706

By Michael Washington on   8/8/2010 6:48 AM
Gravatar

Re: Deleting A Silverlight DataGrid Row With A Button On The Row

Hello,
You can also use EventToCommand of MVVM light toolkit.

By VahidN on   8/8/2010 12:51 PM
Gravatar

Re: Deleting A Silverlight DataGrid Row With A Button On The Row

You can also use the BindingHelper code from www.scottlogic.co.uk/blog/colin/2009/02/relativesource-binding-in-silverlight/ to get a reference to the ViewModel associated with the DataGrid's parent view, and assuming you have a SelectedItem there, you'll then be able to process that with an ICommand/Delegate combination. I do the same for an edit button as well.

By Bob Baker on   8/10/2010 12:55 PM

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
  
Copyright 2009 by OpenLightGroup.net   |  Privacy Statement  |  Terms Of Use