MVVM and gridview saving change (RIA Services)

13 posts, 0 answers
  1. Pierre
    Pierre avatar
    212 posts
    Member since:
    Apr 2007

    Posted 04 May 2010 Link to this post

    hi everyone, i work a new projet that use MVVM, RIA service and Telerik silverlight control.

    Like RIA are not supported yet by OpenAccess ORM, I use the EntityFramework for now.
    My Model read the data like:
            public void GetTypeAdhesionAsync()  
            {  
                Context.TypeAdhesions.Clear();  
     
                var qry = Context.GetTypeAdhesionQuery();  
     
                var loadOperation = Context.Load<TypeAdhesion>(qry, GetTypeAdhesionCallBack, null);  
            }  
     
            void GetTypeAdhesionCallBack(LoadOperation<TypeAdhesion> loadOperation)  
            {  
                try 
                {  
                    if (loadOperation.HasError)  
                    {  
                        GetTypeAdhesionComplete(thisnew EntityResultsArgs<TypeAdhesion>(loadOperation.Error));  
                    }  
                    else if (loadOperation.Entities.Count() > 0)  
                    {  
                        GetTypeAdhesionComplete(thisnew EntityResultsArgs<TypeAdhesion>(Context.TypeAdhesions));  
                    }  
                }  
                catch (Exception ex)  
                {  
     
                    GetTypeAdhesionComplete(thisnew EntityResultsArgs<TypeAdhesion>(ex));  
                }  
            } 

    Like I need the insert/delete I transfert the result in ObservableCollection in the VIewModel:
            void _model_GetTypeAdhesionComplete(object sender, EntityResultsArgs<TypeAdhesion> e)  
            {  
                if (e.Error != null)  
                {  
                    //ErrorMessage = e.Error.Message;  
                }  
                else 
                {  
                    m_TypeAdhesions.Clear();  
                    foreach (TypeAdhesion ta in e.Results) m_TypeAdhesions.Add(ta);  
     
                }  
                IsLoading = false;  
            } 

    like I need paging I wrap all this into a PagedCollectionView
            private ObservableCollection<TypeAdhesion> m_TypeAdhesions;  
            private PagedCollectionView m_TypeAdhesionsPC;  
            public PagedCollectionView TypeAdhesions  
            {  
                get { return m_TypeAdhesionsPC; }  
                private set 
                {  
                    if (value != m_TypeAdhesionsPC)  
                    {  
                        m_TypeAdhesionsPC = value;  
                        RaisePropertyChanged("TypeAdhesions");  
                    }  
                }  
            } 
    All this is bind to a Gridview and rad pager
    All work good, But how I can send the modification back to DB with RIA?
    Do I need to raise a collectionchange event on the ObservableCollection and then call the proper function Add, Del, Insert of my RIA context?

    Thanks for your help.
  2. Stefan Dobrev
    Admin
    Stefan Dobrev avatar
    790 posts

    Posted 05 May 2010 Link to this post

    Hi Pierre,

    Please find attached a sample project which illustrates how to achieve save functionality with MVVM. A command is exposed in the sample view model which persists the changes via SubmitChanges method on the DomainContext. Also you can see how paging can be implemented without PagedCollectionView.

    Hope you will find this useful,
    Stefan Dobrev
    the Telerik team

    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
  3. DevCraft banner
  4. Pierre
    Pierre avatar
    212 posts
    Member since:
    Apr 2007

    Posted 05 May 2010 Link to this post

    Thanks for reply.

    What the drawback of using the RadObsevableCollection? We go the same speed and fonctionnality? When using RadObservableCollection we can omit to warp it with PagedCollectionView?

    i don't understand why your property look like:
            public IEnumerable Artists   
            {  
                get 
                {  
                    if (this.artists == null)  
                    {  
                        this.artists = new RadObservableCollection<Artist>();  
     
                        this.context.Load(this.context.GetArtistsQuery(), LoadArtistsCompleted, null);  
                    }  
     
                    return artists;  
                }  
            } 
    Returning a IEnumerable instead of RadObservableCollection. And why I can remove and edit with a binding to a IEnumerable?
    I try replacing the IEnumerable with a RadObservableCollection and that work too. Witch one are the best choice?
    Because with a code like:
            public RadObservableCollection<TypeAdhesion> TypeAdhesions  
            {  
                get { return m_TypeAdhesions; }  
                set 
                {  
                    if (value != m_TypeAdhesions)  
                    {  
                        m_TypeAdhesions = value;  
                        RaisePropertyChanged("TypeAdhesions");  
                    }  
                }  
            } 
    I can RaisePropertyChanged and then use
    TypeAdhesions.Clear();  
    TypeAdhesions.AddRange(e.Results);  
    m_TypeAdhesions.CollectionChanged += TypeAdhesion_CollectionChanged;  
     
    foreach (TypeAdhesion ta in e.Results) ta.PropertyChanged += TypeAdhesion_PropertyChanged; 
    And be sure my binded control receive notification for the clear and the AddRange.

    What is the purpose of using a partial class Artist.cs in the client side project? I see that youadd a new albumchange event instead of using the propertychanged default event? But why?
  5. Pierre
    Pierre avatar
    212 posts
    Member since:
    Apr 2007

    Posted 06 May 2010 Link to this post

    Ok, after several Try & error I came to this solution to support my MVVM pattern.

    ViewModel:
            void _model_GetTypeAdhesionComplete(object sender, EntityResultsArgs<TypeAdhesion> e)  
            {  
                if (e.Error != null)  
                {  
                    //ErrorMessage = e.Error.Message;  
                }  
                else  
                {  
                    TypeAdhesions.Clear();  
                    TypeAdhesions.AddRange(e.Results);  
                    m_TypeAdhesions.CollectionChanged += TypeAdhesion_CollectionChanged;  
     
                    foreach (TypeAdhesion ta in e.Results) ta.PropertyChanged += TypeAdhesion_PropertyChanged;  
     
                }  
                IsLoading = false;  
            }  
     
     
            void TypeAdhesion_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)  
            {  
                switch (e.Action)  
                {  
                    case NotifyCollectionChangedAction.Add:                       
    TypeAdhesion Item = (TypeAdhesion)e.NewItems[0];  
                        Item.PropertyChanged += TypeAdhesion_PropertyChanged;  
                        break;  
                    case NotifyCollectionChangedAction.Remove:  
                         TypeAdhesion ItemOld = (TypeAdhesion)e.OldItems[0];  
                        ItemOld.PropertyChanged -TypeAdhesion_PropertyChanged;  
                        m_Model.EnleveTypeAdhesion(ItemOld);  
                        break;  
                    case NotifyCollectionChangedAction.Reset:  
                    default:  
                        break;  
                }  
     
            }  
            private void TypeAdhesion_PropertyChanged(object sender, PropertyChangedEventArgs e)  
            {  
                TypeAdhesion Item;  
                Item = (TypeAdhesion)sender;  
     
                switch (Item.EntityState)  
                {  
                    case System.ServiceModel.DomainServices.Client.EntityState.Modified:    
                          break;  
     
                    case System.ServiceModel.DomainServices.Client.EntityState.Detached:    
                        if (!Item.HasValidationErrors)   
                        {  
                            m_Model.AjouteTypeAdhesion(Item);  
                        }  
                        break;  
                }  
            } 
    My MODEL file:
            public void EnleveTypeAdhesion(TypeAdhesion Item)  
            {  
                Context.TypeAdhesions.Remove(Item);  
                Context.SubmitChanges();  
            }  
     
            public void AjouteTypeAdhesion(TypeAdhesion Item)  
            {  
                Context.TypeAdhesions.Add(Item);  
                Context.SubmitChanges(OnSubmitCompleted,null);  
            } 
    The remove part work good. But I can't add a new row. I always got this error on the Context.SubmitChanges:
    "Entity 'TypeAdhesion : 0' is currently being edited and has uncommitted changes. A call to BeginEdit must be followed by a call to EndEdit or CancelEdit before changes can be submitted."

    Do I have a way to commit the change from the viewmodel before calling my add function from the model?

    Maybe I do not update the wright way?
    I do not understand well If I wrap the Entity (iEnumerable) in the RadObservableCollection:
    1- How I can Add a new item in the RadObservableCollection, then update the Entity context, retreive the ID (My sql source use Identity column) and then update the correct ID in the RadObservableColletion
    2- How I can Modifiy a item in the RadObservableColletion, "attach" to the same item in the Entity context to propagate change and then sumbit to DB
    In you demo, you juste remove and add new item, but you do not work with modified one.

    Please help.

  6. Stefan Dobrev
    Admin
    Stefan Dobrev avatar
    790 posts

    Posted 11 May 2010 Link to this post

    Hi Pierre,

    RIA Services will handle the editing for you out of the box. In order to avoid the exception you are getting currently you should first commit the pending edit. You can do this by calling RadGridView.Items.CommitEdit() method, before calling the add method.

    RIA will automatically handle the ID (identity) propagating for you on the client. Everything you need to do is to add/attach the item from the current context and then submit the changes.

    All the best,
    Stefan Dobrev
    the Telerik team

    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
  7. Pierre
    Pierre avatar
    212 posts
    Member since:
    Apr 2007

    Posted 19 May 2010 Link to this post

    Ok but how i can call the RadGridView.Items.CommitEdit() method without broking the MVVM ? The RadObservable collection are in my ViewModel the are not aware of control in the view. The radGridView are not accessible from my viewmodel file!
  8. Stefan Dobrev
    Admin
    Stefan Dobrev avatar
    790 posts

    Posted 20 May 2010 Link to this post

    Hi Pierre,

    You can expose collection implementing IEdtiableCollectionView. The method CommitEdit() is on this interface and will be called by RadGridView when the edit is finished. Actually this is what RIA's DomainDataSource is doing - it is exposing a collection view, which is IEditableCollectionView.

    Greetings,
    Stefan Dobrev
    the Telerik team

    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
  9. Pierre
    Pierre avatar
    212 posts
    Member since:
    Apr 2007

    Posted 20 May 2010 Link to this post

    Can you provide juste a few line to show how to implement IEditableCollectionView with RadObservableCollection? How I define it? For now I got:

            private RadObservableCollection<TypeAdhesion> m_TypeAdhesions;  
            public RadObservableCollection<TypeAdhesion> TypeAdhesions  
            {  
                get { return m_TypeAdhesions; }  
                set  
                {  
                    if (value != m_TypeAdhesions)  
                    {  
                        m_TypeAdhesions = value;  
                        RaisePropertyChanged("TypeAdhesions");  
                    }  
                }  
            } 

  10. Bryan
    Bryan avatar
    28 posts
    Member since:
    Jul 2008

    Posted 22 May 2010 Link to this post

    How do you delete using your MVVM example without code behind?
  11. Pierre
    Pierre avatar
    212 posts
    Member since:
    Apr 2007

    Posted 25 May 2010 Link to this post

    Can someone answer y question?

    If i wrap the RadObeservableCollection with a PageCollectionView I will have the IEditableCollectionView ?
    I could't found the correct way to intercept add, modified and remove event to transfert the info tho my RIA context...
    With PageCollectionView the CollectionChanged event call remove then add for modifief item!!!

    Please help.
  12. Stefan Dobrev
    Admin
    Stefan Dobrev avatar
    790 posts

    Posted 26 May 2010 Link to this post

    Hi all,

    Please find attached an updated version of the project which illustrates how this can be implemented with custom editable collection view implementation. This collection view exposes a couple of events that can be used for further customizations.

    Hope this helps,
    Stefan Dobrev
    the Telerik team

    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items.
  13. Pierre
    Pierre avatar
    212 posts
    Member since:
    Apr 2007

    Posted 13 Jul 2010 Link to this post

    So, correct me if  i am wrong:

    Normally when a RIA entity is copied from the RIA Context to a RadObservableCollection with the addRange function, if this item is modified in the grid and I call the Context.SubmitChange, the change are commited becase the entoty still "attached" the the RIA context ethier the copy process to another collection. Wright?

    But If I add, or Remove item in the grid, I need to get the event to add or remove in the RIA context (Contex.Add) the new entity. Without that, when the SubmitChange will arrive the new added or deleted entity will not be comited?

    In you last example, you do not use RadObservableColletion anymore, you are using EntityCollectionViewBase that is a custom collection type. I do not see add or remove event in you code. This custom collection will handle the add and remove from the grid and send it to the RIA context? Or I need to handle these event to add or remove in the RIA context?

    I found some information ont he EntityCollectionViewBase on The Elephant web site (http://www.riaservicesblog.net/Blog/post/WCF-RIA-Services-Speculation-EntityCollectionView.aspx) But do you have more information on this collection (more a MVVM DDS class).
  14. Milan
    Admin
    Milan avatar
    1989 posts

    Posted 14 Jul 2010 Link to this post

    Hi Pierre,

    The custom EntityCollectionView will also handle the add and remove and will send it to the Ria context, if of course, the changes are submitted using the Submit button (Submit operation). 

    Sincerely yours,
    Milan
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Back to Top
DevCraft banner