Strategy for RO change notification - Silverlight Client

Strategy for RO change notification - Silverlight Client

Old forum URL: forums.lhotka.net/forums/t/7416.aspx


FraggleRocks posted on Friday, August 07, 2009

Sorry if this seems a bit basic, but we have have been going around in circles and I can't decide which route is best practice:

Our Scenario is:
Editable List of "Customers" with Parent and Child Items.
Plus a second editable list of "Invoices".

The customer editor displays a Read only list of invoices for that customer. The RO List issourced from a view. Invoice edits are independent actions from customer edits.

After updating an invoice (i.e. launching child page, editing invoice, closing child page) I need the RO List of invoices to be refreshed on the client.
I have tried one solution which cached all instances of my RO List, and when an Invoice BO is created, updated, or deleted it notified the cached instances of the RO List that they need to be refreshed. I can get this to happen business-logic side and the data is re-read, but when I fire the “ListChanged” event the client does not update (presumably because it is a read-only list and hence not expected to change?).
I have read 2 posts on Notification http://forums.lhotka.net/forums/thread/16447.aspx AND
http://forums.lhotka.net/forums/thread/34467.aspx but I need a bit more direction.
I think I have several options, I was wondering if anyone had done any of these successfully, or am I breaking the philosophy of the framework and doing something unwise? I am looking for an elegant solution. The options I can think of are:
1. Extend my RO List class to support INotifyPropertyChanged and raise the event instead of the ListChanged event?
2. Change my ReadOnlyList to be editable to get the events I need (I don’t like this one!).
3. Create a new base class ReadOnlyListNotifyingOnChange, based on ReadOnlyListBase genericise the problem using INotifyPropertyChanged
4. Create my own event and event handler pair and invoke it in the UI somehow?

Any advice?

RockfordLhotka replied on Friday, August 07, 2009

On the SL side of things it is the CollectionChanged event you need, not ListChanged.

The ROLB class ultimately inherits from ObservableCollection<T>, just like BLB. This means your collection already supports change notification as expected by Silverlight.

To trigger the event, call OnCollectionChanged(). Please note that one CSLA enhancement is that collections support RaiseListChangedEvents like in .NET, so make sure you don't have events turned off, otherwise OnCollectionChanged() don't do anything.

FraggleRocks replied on Friday, August 07, 2009

I think I am missing something fundemental.
It seems to me that the OnCollectionChanged method is only available Silverlight side.

What I have done is: Determine that the RO list needs to be re-read in the #if !Silverlight (business logic), by monitoring for "related" data changing by extending data_portal create update and delete. The idea being that any part of the presentation layer that updates an invoice would cause all RO Lists showing that data to be re-read. i.e. not dependant on coder remembering to add special re-fresh code in the UI.

Have I done this all wrong? should I have made all of my monitoring in #if SILVERLIGHT blocks?

Sorry I am obviously doing something wrong here....

RockfordLhotka replied on Friday, August 07, 2009

I don't know what you are doing wrong :)

It is true that OnCollectionChanged() is SL only, because the .NET classes
inherit from BindingList to provide support for Windows Forms. No need
for that on SL.

The thing is, if you are detecting that an invoice was saved, and that
triggers reloading your ROL objects via the data portal, you will get back
NEW ROL LIST OBJECTS.

So raising a changed event is immaterial, because it isn't even the same
list. The UI would still be referencing the old list, not the new one you
just got from the data portal. So saying "the list changed" isn't really
correct, because it didn't change - it was replaced.

If that's the case (and I suspect it is), then you need some way to tell the
UI that the list itself is new.

This is where a data provider or view model object (basically the same idea)
come into play.

Such an object exposes the list as a property (like the Data property of a
CslaDataProvider). You can replace the list, and then raise PropertyChanged
on the data provider to tell the UI that the Data property changed, so it
refreshes its binding to that property and thus gets the new list. The
CslaDataProvider does this exact thing and it works fine.

So the trick is to have some intermediary object (data provider or view
model) that the XAML binds to, and have that object raise PropertyChanged
when the ROL property changes.

Rocky

Jack replied on Monday, August 24, 2009

Rocky,

I'm trying to do something similar... I have a ROL that I like to append to or merge in updates.  Its a master list used by a number of objects.  I'm turning off the RaiseListChangedEvents so I can do bulk changes but once its done I want to tell the world that the list has changed.

Is there anyway to have a generic notification from within the ROL?  I've added this Merge as a method in the ROL.  I can add the OnCollectionChanged but I have to wrap it in #IF Silverlight...

public void Merge(IEnumerable<ObjectInfo> updatedList)
        {
            RaiseListChangedEvents = false;

            IsReadOnly = false;

            // identify all the duplicate records
            var existingList = (from currentData in this
                                join updatedData in updatedList
                                    on currentData.ObjectId equals updatedData.ObjectId
                                select currentData).ToObservableCollection();

            // look through the list and remove any duplicates
            foreach (var updatedObject in existingList) Remove(updatedObject);

            AddRange(updatedList);

            IsReadOnly = true;
           
            RaiseListChangedEvents = false;

            //OnPropertyChanged(new PropertyChangedEventArgs(String.Empty));

#if SILVERIGHT
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
#endif

        }
thanks

jack

RockfordLhotka replied on Monday, August 24, 2009

On the Silverlight side it is OnCollectionChanged(), and on the .NET side it is OnListChanged().

 

OnListChanged() has a reset option – so you can indicate that databinding should reset its connection to the list. I don’t know if CollectionChanged has an equivalent.

 

Rocky

 

Jack replied on Monday, August 24, 2009

Sorry - I was sort of suggesting maybe we could add something to the framework so I didn't have to add both to my call.

 

Something along the lines of the way to SetProperties without trigger OnPropertyChanged is done (I can't remember the flag name off hand).

 

 

So instead of

 

RaiseListChangedEvents = false

...

RaiseListChangedEvents = true

 

if#Silverlight

      OnCollectionChanged()

else

      OnListChanged()

end if

 

 

using (DontRaiseListChangedEvents(true))

{

...

}

 

if true then in the dispose it will fire off the OnCollectionChanged a single time.

 

From: Rockford Lhotka [mailto:cslanet@lhotka.net]
Sent: August-24-09 3:10 PM
To: jaddington@alexandergracie.com
Subject: RE: [CSLA .NET] RE: Strategy for RO change notification - Silverlight Client

 

On the Silverlight side it is OnCollectionChanged(), and on the .NET side it is OnListChanged().

 

OnListChanged() has a reset option – so you can indicate that databinding should reset its connection to the list. I don’t know if CollectionChanged has an equivalent.

 

Rocky

 



FraggleRocks replied on Tuesday, October 13, 2009

It has taken me a while to find the time to look at this problem again. Having read Rocky’s post above I tried the following:
Made my ReadOnlyList a child property of my Client Business Object:
private static PropertyInfo ROInvoicesForClientProperty = RegisterProperty(new PropertyInfo("ROInvoicesForClient", "Read Only Invoices For Client"));
public ROClientInvoiceList ROInvoicesForClient
{
get { return GetProperty(ROInvoicesForClientProperty); }
}
Add a static event with id parameters (non silverlight side) that is called whenever a list member changes. The Client BO listens for the event and if the ids match re-reads the child list data. It then calls:
OnPropertyChanged("ROInvoicesForClient");
However the client never gets notified and the data displayed does not update. I was trying to use existing CSLA classes whereever possible.
Can anybody offer some advice on what to try next? I keep looking at this and can not see what is wrong. Maybe it cannot be done with the CSLA classes and I need to get to grips with the new stuff in V3.8 beta? I am using CSLA light V3.7 with silverlight.

RockfordLhotka replied on Tuesday, October 13, 2009

You say that the static event is "non silverlight side", which sounds like the event is on your server.

Events don't flow across network boundaries as a general rule. If you want events to flow across network boundaries you need to create a specialized WCF service configuration to flow and handle the event. Flowing events also limits the types of WCF bindings you can use because most bindings don't support this concept.

On the client side, the UI won't refresh unless the client side business object raises a changed event.

RockfordLhotka replied on Tuesday, August 25, 2009

http://www.lhotka.net/cslabugs/edit_bug.aspx?id=538

Jack replied on Tuesday, August 25, 2009

Thank you

 

From: RockfordLhotka [mailto:cslanet@lhotka.net]
Sent: August-25-09 7:40 AM
To: jaddington@alexandergracie.com
Subject: Re: [CSLA .NET] Strategy for RO change notification - Silverlight Client

 

http://www.lhotka.net/cslabugs/edit_bug.aspx?id=538

Copyright (c) Marimer LLC