views:

85

answers:

1

Hi.

I may be confused about the purpose behind INotifyPropertyChanged and Silverlight...

I have XAML that I created in the designer:

<UserControl.Resources>
    <CollectionViewSource x:Key="theViewSource" d:DesignSource="{d:DesignInstance my:transferObject, CreateList=True}" />
</UserControl.Resources>

as well as this

            <Canvas DataContext="{StaticResource theViewSource}">
                <sdk:DataGrid ItemsSource="{Binding}" Name="theDataGrid">
                    <sdk:DataGrid.Columns>
                     <!-- columns omitted from post -->
                    </sdk:DataGrid.Columns>
                </sdk:DataGrid>
            </Canvas>

And I also have some codebehind:

Private Sub control_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
    If Not (System.ComponentModel.DesignerProperties.GetIsInDesignMode(Me)) Then
        Dim myCollectionViewSource As System.Windows.Data.CollectionViewSource =
            CType(Me.Resources("theViewSource"), System.Windows.Data.CollectionViewSource)

        Dim myViewModel As New ViewModels.ViewModelThatHasAnObservableCollectionProperty()

        myCollectionViewSource.Source = myViewModel.TheObservableCollection()
    End If
End Sub

And a ViewModel that looks somewhat like this:

Public Class ViewModelBase
    Implements ComponentModel.INotifyPropertyChanged

    Protected Sub RaisePropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class

Public Class ViewModelThatHasAnObservableCollectionProperty
    Inherits ViewModelBase

    Public Sub RetrieveCollectionCompletedHandler(ByVal sender As Object, ByVal e As SilverlightConsumableService.RetrieveMyCollectionCompletedEventArgs)
        Dim unobservable As List(Of TransferObjects.TheTransferObject) = e.Result

        'I was hoping for this next line of code to force a refresh of the DataGrid
        TheObservableCollection = New ObservableCollection(Of TransferObjects.transferObject)(unobservable)
    End Sub

    Public Sub New()
        Dim theClient As New SilverlightConsumableService.SilverlightConsumableSoapClient

        AddHandler theClient.RetrieveMyCollectionCompleted, AddressOf RetrieveCollectionCompletedHandler

        theClient.RetrieveMyCollectionAsync()
    End Sub

    Private _theObservableCollection As ObservableCollection(Of TransferObjects.transferObject)
    Public Property TheObservableCollection() As ObservableCollection(Of TransferObjects.transferObject)
        Get
            Return _theObservableCollection
        End Get
        Set(ByVal value As ObservableCollection(Of TransferObjects.transferObject))
            _theObservableCollection = value
            RaisePropertyChanged("TheObservableCollection")
        End Set
    End Property
End Class

The result is that Silverlight renders the datagrid with no results because TheObservableCollection hasn't been populated by the event handler yet. That's to be expected. What I was hoping for was that after the asychronous call to the web service, the Setter for TheObservableCollection gets called, and subsequently so does RaisePropertyChanged.

My expectation was that Silverlight would handle this by rebinding the dataGrid to the property... Isn't the purpose behind using INotifyPropertyChanged to make it so that I don't have to rebind the grid programmatically, or am I confused about that?

A: 

In Silverlight (unlike WPF), you don't assign the ObservableCollection in your service response handler. This will break the binding.

Instead, clear out the already bound collection and re-populate it with the items from your service response. Updating the collection will properly raise the notification events. If you re-assign the collection's reference, the binding to the UI element will be broken.

The purpose behind INotifyPropertyChanged is to inform any bound members that the value of the property changed. In the case of collections, re-assigning the reference does not count as a value change. Updating the number of collection members does. Likewise, changing individual properties will raise the notify events as long as you call the PropertyChanged event. The purpose of the interface is to provide a contract for the View to listen to the ViewModel.

j0rd4n
You are correct. If I clear the values out and populate the collection anew instead of using the setter, it works as expected. Thanks!
Jason
If @j0rd4n answered your question please remember to mark it as such.
Andy May

related questions