none
Overloading SubmitChanges to implement CollectionChanged event on a DataContext RRS feed

  • Question

  • ok in my code file for my schema I created methods that return a class that inherits observable collection then i extended it to add a few biz layer features.

    Public ReadOnly Property Departments() As LinqBindingList(Of BudgetDB.tbl_Department)
            Get
                If _Departments Is Nothing Then _
                    _Departments = New LinqBindingList(Of BudgetDB.tbl_Department)(Me.GetTable(Of BudgetDB.tbl_Department)().ToList)
                Return _Departments
            End Get
        End Property
    


    so i did this for nearly every table i plan on using in my WPF app and this all works great. i can now add and remove objects and the ui updates as expected. however While this works i believe it is a gross mismanagment of memory and i would like to optimize it. so i came up with the idea to just make the datacontext implement INotificationchanged so i can use the existing objects and just extend them a bit. then I overloaded SubmitChanges so I can invoke the collectionchanged event on each of the lists however while I can handle this event in my ui the data is not updating. here is the submitchanges code i created.

    Public Overloads Sub SubmitChanges()
            Dim Changes As System.Data.Linq.ChangeSet = MyBase.GetChangeSet()
            If Changes.Inserts.Count > 0 Then
                For Each Inserted As Object In Changes.Inserts
                    Dim InsertedEvent As New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, Inserted)
                    RaiseEvent CollectionChanged(Me.tbl_Departments, InsertedEvent)
                Next
            End If
    
            If Changes.Deletes.Count > 0 Then
                For Each Deleted As Object In Changes.Deletes
                    Dim DeletedEvent As New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, Deleted)
                    RaiseEvent CollectionChanged(Me.tbl_Departments, DeletedEvent)
                Next
            End If
            MyBase.SubmitChanges()
        End Sub
    



    I have also tried doing it without a for each loop and just passing in the collection into the event arg but end in the same result. it seems like this is possible without duplicating the data is there something im missing? The only thing i can think of is the table object which im raising the event in is not the same object my ui is using however they seem to be the same because the data is in there the ui is just not updating to display the changes. Is this method possible or should i just still with the observable collection method that duplicates the data?

    Friday, September 11, 2009 2:00 PM

Answers

  • yeah i figured out i was going about it in the wrong direction. I was able to fully implement Observable Collections with linq without using bindable linq or any of the other 3rd party sources out. all i had to do was create a class that inherited from a list and then ensure it implmented inotifycollectionchanged and then in the data context i overrided the inserted/deleted methods of each table and  then have it add the entity to the new collection when an insert or delete occurred. I was pretty stoked when i finaly got it working the way i wanted. The following code is what i did to achieve it. for others that may want to use linq with a WPF treeview that need to the ability to add and remove nodes on the fly. The only thing i dont like about the way i did it is i have to bind the wpf treeview directly to the DAL to achieve the result without duplicating a ton of code.



    Partial Public Class LinqBindingList(Of T)
        Inherits List(Of T)
        Implements INotifyCollectionChanged
        Implements INotifyPropertyChanged
    
        Public Event CollectionChanged(ByVal sender As Object, ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs) Implements System.Collections.Specialized.INotifyCollectionChanged.CollectionChanged
        Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    
        Public Shadows Sub Add(ByRef value As T)
            MyBase.Add(value)
            RaiseEvent CollectionChanged(Me, New Specialized.NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value))
        End Sub
    
        Public Shadows Sub Remove(ByRef value As T)
            MyBase.Remove(value)
            RaiseEvent CollectionChanged(Me, New Specialized.NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, value))
        End Sub
    End Class

    Partial Class BudgetDBDataContext
        Private _Departments As LinqBindingList(Of BudgetDB.tbl_Department)
    
        Public ReadOnly Property Departments() As LinqBindingList(Of BudgetDB.tbl_Department)
            Get
                If _Departments Is Nothing Then
                    _Departments = New LinqBindingList(Of BudgetDB.tbl_Department)
                    _Departments.AddRange(Me.tbl_Departments)
                End If
                Return _Departments
            End Get
        End Property
    
        Private Sub Inserttbl_Department(ByVal instance As BudgetDB.tbl_Department)
            _Departments.Add(instance)
            Me.ExecuteDynamicInsert(instance)
        End Sub
        Private Sub Deletetbl_Department(ByVal instance As BudgetDB.tbl_Department)
            _Departments.Remove(instance)
            Me.ExecuteDynamicDelete(instance)
        End Sub
    
        Private Sub Inserttbl_Division(ByVal instance As BudgetDB.tbl_Division)
            instance.tbl_Department.Divisions.Add(instance)
            Me.ExecuteDynamicInsert(instance)
        End Sub
        Private Sub Deletetbl_Division(ByVal instance As BudgetDB.tbl_Division)
            instance.tbl_Department.Divisions.Remove(instance)
            Me.ExecuteDynamicDelete(instance)
        End Sub

    End Class
        Partial Class tbl_Department
            Private _Divisions As LinqBindingList(Of BudgetDB.tbl_Division)
    
            Public ReadOnly Property Divisions() As LinqBindingList(Of BudgetDB.tbl_Division)
                Get
                    If _Divisions Is Nothing Then
                        _Divisions = New LinqBindingList(Of BudgetDB.tbl_Division)
                        _Divisions.AddRange(Me.tbl_Divisions)
                    End If
                    Return _Divisions
                End Get
            End Property
        End Class



    I hope this helps another person who is having the same issue. There seem to be quite a few ppl out there that ran into this issue but most of the solutions are to use a 3rd party dll and unfortunatly with the work I do i am prohibited from using any code that was not written by me or i do not have the source code for(for security purposes). The only downfall of the system I have is im executing the submit after the linqbinding list has been changed and if an error occurs i dont have any error handling to undo the changes but ill work on that later when i have more time lol. I implemented this system on a hiearchical table structure of about 9 layers deep meaning my treeview can go as deep as 9 nested nodes and still support lazy loading.


    Thanks Lingzhi sun for your help.
    Thursday, September 17, 2009 4:25 PM

All replies

  • Hi Chrissteven81,

     

    Glad to see you again!

     

    Could you please provide me with more detailed information about how you implemented the INotificationChanged interface?   The demo project and some testing data would be really helpful.

     

    Hope you have a nice day!

     

     

    Best Regards,
    Lingzhi Sun


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, September 14, 2009 3:07 AM
    Moderator
  • I figured it out over the weekend. the problem was that the linq.tables would fire the event however the entity sets would not. This is because i throught that the entity sets where just filters for the table in the data context but that does not seem to be the case they are by. in any case the way i solved the problem was to add a handler to the individual classes for each entityset they expose using the ListChanged event. This allows me to handle the change and raise an event in my biz layer letting the ui know through the observable collection. I'll see if i can get time to generate a small demo in a bit around lunch time.
    Monday, September 14, 2009 12:24 PM
  • Hi Chrissteven81,

     

    How is the problem now?  Is it has been resolved?   If you need further assistance, please feel free to tell me.
     

    Hope you have a nice day!

     

     

    Best Regards,
    Lingzhi Sun


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Thursday, September 17, 2009 9:10 AM
    Moderator
  • yeah i figured out i was going about it in the wrong direction. I was able to fully implement Observable Collections with linq without using bindable linq or any of the other 3rd party sources out. all i had to do was create a class that inherited from a list and then ensure it implmented inotifycollectionchanged and then in the data context i overrided the inserted/deleted methods of each table and  then have it add the entity to the new collection when an insert or delete occurred. I was pretty stoked when i finaly got it working the way i wanted. The following code is what i did to achieve it. for others that may want to use linq with a WPF treeview that need to the ability to add and remove nodes on the fly. The only thing i dont like about the way i did it is i have to bind the wpf treeview directly to the DAL to achieve the result without duplicating a ton of code.



    Partial Public Class LinqBindingList(Of T)
        Inherits List(Of T)
        Implements INotifyCollectionChanged
        Implements INotifyPropertyChanged
    
        Public Event CollectionChanged(ByVal sender As Object, ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs) Implements System.Collections.Specialized.INotifyCollectionChanged.CollectionChanged
        Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    
        Public Shadows Sub Add(ByRef value As T)
            MyBase.Add(value)
            RaiseEvent CollectionChanged(Me, New Specialized.NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value))
        End Sub
    
        Public Shadows Sub Remove(ByRef value As T)
            MyBase.Remove(value)
            RaiseEvent CollectionChanged(Me, New Specialized.NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, value))
        End Sub
    End Class

    Partial Class BudgetDBDataContext
        Private _Departments As LinqBindingList(Of BudgetDB.tbl_Department)
    
        Public ReadOnly Property Departments() As LinqBindingList(Of BudgetDB.tbl_Department)
            Get
                If _Departments Is Nothing Then
                    _Departments = New LinqBindingList(Of BudgetDB.tbl_Department)
                    _Departments.AddRange(Me.tbl_Departments)
                End If
                Return _Departments
            End Get
        End Property
    
        Private Sub Inserttbl_Department(ByVal instance As BudgetDB.tbl_Department)
            _Departments.Add(instance)
            Me.ExecuteDynamicInsert(instance)
        End Sub
        Private Sub Deletetbl_Department(ByVal instance As BudgetDB.tbl_Department)
            _Departments.Remove(instance)
            Me.ExecuteDynamicDelete(instance)
        End Sub
    
        Private Sub Inserttbl_Division(ByVal instance As BudgetDB.tbl_Division)
            instance.tbl_Department.Divisions.Add(instance)
            Me.ExecuteDynamicInsert(instance)
        End Sub
        Private Sub Deletetbl_Division(ByVal instance As BudgetDB.tbl_Division)
            instance.tbl_Department.Divisions.Remove(instance)
            Me.ExecuteDynamicDelete(instance)
        End Sub

    End Class
        Partial Class tbl_Department
            Private _Divisions As LinqBindingList(Of BudgetDB.tbl_Division)
    
            Public ReadOnly Property Divisions() As LinqBindingList(Of BudgetDB.tbl_Division)
                Get
                    If _Divisions Is Nothing Then
                        _Divisions = New LinqBindingList(Of BudgetDB.tbl_Division)
                        _Divisions.AddRange(Me.tbl_Divisions)
                    End If
                    Return _Divisions
                End Get
            End Property
        End Class



    I hope this helps another person who is having the same issue. There seem to be quite a few ppl out there that ran into this issue but most of the solutions are to use a 3rd party dll and unfortunatly with the work I do i am prohibited from using any code that was not written by me or i do not have the source code for(for security purposes). The only downfall of the system I have is im executing the submit after the linqbinding list has been changed and if an error occurs i dont have any error handling to undo the changes but ill work on that later when i have more time lol. I implemented this system on a hiearchical table structure of about 9 layers deep meaning my treeview can go as deep as 9 nested nodes and still support lazy loading.


    Thanks Lingzhi sun for your help.
    Thursday, September 17, 2009 4:25 PM
  • Hi Chrissteven81,

    Fantastic!  Your codes are definitely helpful!  It is truly beneficial to other community members who are using LINQ and databingding. 

    We are preparing some LINQ related FAQs for the community recently.  Your post is quite valuable, since LINQ and databinding is one of the frequently asked questions in our community. 

     

    Thank you very much again, hope you have a nice weekend!

     

    Best Regards,
    Lingzhi Sun


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Friday, September 18, 2009 2:08 PM
    Moderator