This project has moved. For the latest updates, please go here.

PropertyChanged

Developer
Apr 16, 2013 at 4:29 PM
Edited Apr 16, 2013 at 6:39 PM
How do raise the PropertyChanged event from a child collection to the parent? I have a standard invoice with detail lines as followings. I want to raise the 'PropertChanged' event whenever there are changes in the 'InvoiceDetailListItem'.
class Invoice : BusinessBase<Invoice>
class InvoiceDetailList : BusinessBindingListBase<InvoiceDetailList, InvoiceDetailListItem>
class InvoiceDetailListItem : BusinessBase<InvoiceDetailListItem>
I can get the event as far as the 'InviceDetailList' but don't know how to raise it to 'Invoice'
Coordinator
Apr 17, 2013 at 2:16 AM
Hi Keith,

Did you find the answer? In case you didn't, I suggest you search the CSLA .NET forum. There is a thread some 2 months old about this matter.

Tiago Freitas Leal
Developer
Apr 17, 2013 at 2:22 AM
tiago wrote:
Hi Keith,

Did you find the answer? In case you didn't, I suggest you search the CSLA .NET forum. There is a thread some 2 months old about this matter.

Tiago Freitas Leal
<br/>
I didn't find anything I was able to consume. I've able to override into the 'PropertyHasChanged' event in the DetailListItem and 'Child_PropertyChanged' in the 'InvoiceDetailList' events but can't figure out how to get the event to the root parent (Invoice).
Coordinator
Apr 17, 2013 at 7:42 AM
Developer
Apr 17, 2013 at 2:16 PM
Edited Apr 17, 2013 at 4:18 PM
tiago wrote:
Does this help?
PropertyChanged Help Needed
br/>
Although that article didn't specifically solve my problem it pointed me in the right direction. I needed change the 'Declaration Mode' to 'Classic' and subscribed to the 'ListChanged' event. I've declared the '_detailLines_ListChanged' method in the non-designer file but is there any way to include the hook in the 'InvoiceDetailList' setter?

Thank you very much for your help.
        private InvoiceDetailList _detailLines;
        public InvoiceDetailList DetailLines
        {
            get { return _detailLines; }
            set 
            { 
                _detailLines = value; 
                _detailLines.ListChanged += new ListChangedEventHandler(_detailLines_ListChanged); 
            }
        }

        void _detailLines_ListChanged(object sender, ListChangedEventArgs e)
        {
            ExtendedCost = _detailLines.Sum(x => x.Cost * x.Quantity);
        }
Coordinator
Apr 17, 2013 at 9:36 PM
Hi Keith,

If I understand it correctly, you want to re-calculate the invoice total when the invoice detail lines change. In that case, what you need is a business rule, more specifically a transformation rule.

Business rules are fired whenever the property they are attached to changes. Have a look at CslaGenFork own rules library sample and search the forum. I'm sure you'll find all the info you need.

Tiago Freitas Leal
Developer
Apr 17, 2013 at 10:51 PM
tiago wrote:
Hi Keith,

If I understand it correctly, you want to re-calculate the invoice total when the invoice detail lines change. In that case, what you need is a business rule, more specifically a transformation rule.

Business rules are fired whenever the property they are attached to changes. Have a look at CslaGenFork own rules library sample and search the forum. I'm sure you'll find all the info you need.

Tiago Freitas Leal
<br/>
Thank you. Here is the business rule I created for 'ExtendedCost' in the 'Invoice' class and it is working.
        /// <summary>
        /// Sums extended cost for InvoiceDetailLines
        /// </summary>
        private class SumExtended : BusinessRule
        {
            protected override void Execute(RuleContext context)
            {
                Invoice invoice = (Invoice)context.Target;
                invoice.ExtendedCost = invoice.DetailLines.Sum(x => x.Cost * x.Quantity);
            }
        }
There is also a business rules in the 'InvoiceListItem' class to calculate the extendedCost
        /// <summary>
        /// Calculates extended cost for InvoiceDetailListItem
        /// </summary>
        private class CalcExtended : BusinessRule
        {
            protected override void Execute(RuleContext context)
            {
                var target = (InvoiceDetailListItem)context.Target;

                target.ExtendedCost = target.Quantity * target.Cost;
            }
        }
Developer
Apr 17, 2013 at 11:26 PM
tiago wrote:
Hi Keith,

If I understand it correctly, you want to re-calculate the invoice total when the invoice detail lines change. In that case, what you need is a business rule, more specifically a transformation rule.

Business rules are fired whenever the property they are attached to changes. Have a look at CslaGenFork own rules library sample and search the forum. I'm sure you'll find all the info you need.

Tiago Freitas Leal
<br/>

The only code which I add was to register the 'ListChange' event in 'Invoice'. Initially I put it in the setter of DetailLines (InvoiceList) but this was not getting called so I added to the 'FetchChildren' method. I know changes should not be made to generated files but I could not find a method which could be overridden in the non-designer file. If you have any thoughts I'm all ears

Thanks again for your help.
        /// <summary>
        /// Loads child objects from the given SafeDataReader.
        /// </summary>
        /// <param name="dr">The SafeDataReader to use.</param>
        private void FetchChildren(SafeDataReader dr)
        {
            dr.NextResult();
            LoadProperty(DetailLinesProperty, InvoiceDetailList.GetInvoiceDetailList(dr));
            DetailLines.ListChanged += DetailLines_ListChanged; // WKR [ADDED TO SUBSCRIBE TO ListChange EVENT]
        }
Coordinator
Apr 18, 2013 at 7:24 AM
Edited Apr 18, 2013 at 7:26 AM
RumbleCow wrote:
The only code which I add was to register the 'ListChange' event in 'Invoice'. Initially I put it in the setter of DetailLines (InvoiceList) but this was not getting called so I added to the 'FetchChildren' method. I know changes should not be made to generated files but I could not find a method which could be overridden in the non-designer file. If you have any thoughts I'm all ears
Hi Keith,

Please correct me if I'm wrong but I was expecting the business rule to solve all your problems. Does the rule fire whenever you need to update the invoice sum? I would expect that a single rule on line item's quantity and line item's cost would do all the updates up to the invoice sum. The rule's code can find the invoice and do it (a bit like the NoDuplicates rule in CslagenFork rule library).

If the rule can do all the work there is to be done, why the need to handle events?

Tiago Freitas Leal
Developer
Apr 18, 2013 at 1:42 PM
tiago wrote:
RumbleCow wrote:
The only code which I add was to register the 'ListChange' event in 'Invoice'. Initially I put it in the setter of DetailLines (InvoiceList) but this was not getting called so I added to the 'FetchChildren' method. I know changes should not be made to generated files but I could not find a method which could be overridden in the non-designer file. If you have any thoughts I'm all ears
Hi Keith,

Please correct me if I'm wrong but I was expecting the business rule to solve all your problems. Does the rule fire whenever you need to update the invoice sum? I would expect that a single rule on line item's quantity and line item's cost would do all the updates up to the invoice sum. The rule's code can find the invoice and do it (a bit like the NoDuplicates rule in CslagenFork rule library).

If the rule can do all the work there is to be done, why the need to handle events?

Tiago Freitas Leal
<br/>
What I have found is the business rule on 'Invoice' takes care of the calculating the sum of the line items when the 'InvoiceDetailList' is loaded but is not triggered when the 'InvoiceDetailListItem is changed. Therefore I had to hook up with the 'ListChanged' event. I was hoping there would be an override (the 'Child_Create' override held the most promise but didn't fire) I could use in the non-designer file but was not able to find one so I ended up modifying the generated code in one place (see below).
        /// <summary>
        /// Loads child objects from the given SafeDataReader.
        /// </summary>
        /// <param name="dr">The SafeDataReader to use.</param>
        private void FetchChildren(SafeDataReader dr)
        {
            dr.NextResult();
            LoadProperty(DetailLinesProperty, InvoiceDetailList.GetInvoiceDetailList(dr));
            DetailLines.ListChanged += DetailLines_ListChanged; // <---WKR [ADDED TO SUBSCRIBE TO ListChange EVENT - FIGURE OUT HOW TO GEN]
        }