How to subscribe to parent events from a newly added child object in the business object hierarchy

I'll use the old Invoice example.  Let's say I have a business object hierarchy that looks like this:
Invoice
----- Orders
----------LineItems

Let's say there is a property on the invoice called "Customer".  If I change the customer name, I would like the LineItem object to know about it.  I am unsure how to wire this up to autowire when a LineItem is added to an order.

I guess in the Invoice class I need:

public delegate void CustomerChangedHandler(object sender, CustomerChangedEventArgs e);
public event CustomerChangedHandler CustomerChanged;

public string Customer
{
     get { return _customer; }
     set
     {
                _customer = value;
                OnCustomerChanged();
      }
}

Then in the LineItem class I would need the signature, like:
public void CustomerChanged(object sender, CustomerChangedEventArgs e)
 {
     Debug.Writeline("notified.");
}

The implementation of hte business object looks something like this:

private Invoice _invoice.
.
.
.
LineItem lineItem = new LineItem();
int index = _invoice.Orders[2].LineItems.Add(lineItem);

CustomerChangedHandler  customerHandler = new CustomerChangedHandler(_invoice.Orders[2].LineItems[index].CustomerChanged);

_invoice.CustomerChanged += customerHandler;

This seems to work.  However, this seems incorrect because this eventing wireup is outside of the business object.  How can I wire this up from within the business object when a LineItem is added to the LineItems list?  The challenge here is that it seems I need a reference to Invoice object from this child object.  Either that or some event that would fire within the Invoice object would allow me to add an event subscription for this object.



LVL 1
dentyneAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Bob LearnedCommented:
I need to ask why do you think that you need to do this?

Bob
0
dentyneAuthor Commented:
Well I wanted to have a true business object.  So when someone uses it, if they change some Master data (a subclass of my object one level deep), some other objects n-levels deep in that hierarchy need to recalculate based on this value.  

I didn't want to have to depend on the having to register the events outside the business object because the logic wouldn't be encapsulated anymore.

There are several situations in my obejct in which I'd need this.  For instance, I have a "Products" collection that that some properties.  When a property changes on this collection some things need to recalculate in the individual products in the collection.  There are other situations in which communication is necessary between different levels of business objects.
0
Bob LearnedCommented:
I have heard of business objects encapsulating data, but not events.  I am willing to learn new things.  Generally, I prefer to have a business object be a state object, and the events to happen externally to that.  What you are discovering about how to add events at the business object level might probably give you a hint as to why you wouldn't want to do it that way.  Sometimes, you can come up with an idea, and make it work, and then you're the only that understands it.

bob
0
dentyneAuthor Commented:
Thanks Bob.

This morning I came up with the idea of enforcing a business hierarchy through constructors. Each "child" object then implements a IHierarchy interface (see code snippet).  Could you look at the code and let me know if it makes sense?

I guess I am initially surprised at how little there is on business object hierarchy event encapsulation.  To me (I'm not an expert), the business object hierarchy is the key to the application and they need to talk to each other. I figured the inner communication needed between business objects are like "business rules".

In my dummy example below, if someone changes some "Calculation Method" on the Invoice, then each order for that invoice needs to be recalculated.  (Bad example, but It's too complex to explain my business need).

So using the Invoice example above, it would be:

public class Invoice
{
     private OrderList _orderList;
     private string _calcType;
     //Define the delegate and event to fire when calculation type changes.
     public delegate void CalcTypeChangedHandler(object sender, InvoiceChangedEventArgs e);
     public event CalcTypeChangedHandler CalcTypeChanged;
     
      public Invoice()
      {
            _orderList = new OrderList(this);
      }
     protected void OnCalcTypeChanged()
     {
            if(CalcTypeChanged != null)
                CalcTypeChanged(this,new CalcTypeChangedEventArgs(this._calcType));
        }
     public string CalculationType
     {
          get{ return this._calcType;}
          set
          {
               this._calcType = value;
               OnCalcTypeChanged();
          }
     }
}

Then, in OrderList:

public OrderList : CollectionBase, IBindingList, IHierarchy
{
     private Invoice _parent;

     public OrderList() {}
     public OrderList(Invoice parent)
     {
          _parent = parent;
     }
     public int Add(Order value)
     {
            //Set the parent of the order then wire up the needed events
            value.Parent = this;
            wireUpOrder(value);
            return List.Add(value);
      }
     
      private wireUpOrder(Order order)
      {
            IHierarchy parent = (IHierarchy)this.Parent;
            while (parent != null)
            {
                if (parent.GetType() != typeof(Invoice))
                {
                    parent = (IHierarchy)parent.Parent;
                }
                else
                {
                    //We're at the invoice level.  Wire this order up to listen to it's calctypechanged event
                    Invoice invoice = (Invoice)parent;
                    invoice.CalcTypeChanged += new Invoice.CalcTypeChangedHandler        
                                      (order.CalcTypeChanged);
                }
            }
      }
     #region IHierarchy members
      public object Parent
      {
           get { return this._parent; }
           set { this._parent = (Invoice) value; }
      }
     #endregion
}

Then in the Order:

public class Order : IHierarchy
{
     public void CalcTypeChanged(object sender, InvoiceChangedArgs e)
     {
             Debug.WriteLine("Order is notified of invoice calculation change. Commence recalcs");
     }

     #region IHierarchy members
      public object Parent
      {
           get { return this._parent; }
           set { this._parent = (Invoice) value; }
      }
     #endregion

}

I created the objects and tested their Parent properties and they are all correctly intact.  But I haven't tested the event wiring yet.

I apologize in advance if the code above is incorrect.  I just typed it out.  I have a conversion in my head that translates my real business object  into this Invoice/Order/Item example.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.