This is a migrated thread and some comments may be shown as answers.

MVVM and gridview saving change (RIA Services)

12 Answers 821 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Pierre
Top achievements
Rank 2
Iron
Iron
Pierre asked on 04 May 2010, 09:13 PM
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.

12 Answers, 1 is accepted

Sort by
0
Stefan Dobrev
Telerik team
answered on 05 May 2010, 03:46 PM
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.
0
Pierre
Top achievements
Rank 2
Iron
Iron
answered on 05 May 2010, 09:19 PM
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?
0
Pierre
Top achievements
Rank 2
Iron
Iron
answered on 06 May 2010, 08:03 PM
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.

0
Stefan Dobrev
Telerik team
answered on 11 May 2010, 12:46 PM
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.
0
Pierre
Top achievements
Rank 2
Iron
Iron
answered on 19 May 2010, 07:25 PM
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!
0
Stefan Dobrev
Telerik team
answered on 20 May 2010, 11:52 AM
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.
0
Pierre
Top achievements
Rank 2
Iron
Iron
answered on 20 May 2010, 01:53 PM

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");  
                }  
            }  
        } 

0
Bryan
Top achievements
Rank 1
answered on 22 May 2010, 10:54 PM
How do you delete using your MVVM example without code behind?
0
Pierre
Top achievements
Rank 2
Iron
Iron
answered on 25 May 2010, 01:27 PM
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.
0
Stefan Dobrev
Telerik team
answered on 26 May 2010, 01:11 PM
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.
0
Pierre
Top achievements
Rank 2
Iron
Iron
answered on 13 Jul 2010, 05:14 PM
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).
0
Milan
Telerik team
answered on 14 Jul 2010, 07:10 AM
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
Tags
GridView
Asked by
Pierre
Top achievements
Rank 2
Iron
Iron
Answers by
Stefan Dobrev
Telerik team
Pierre
Top achievements
Rank 2
Iron
Iron
Bryan
Top achievements
Rank 1
Milan
Telerik team
Share this question
or