1. Trang chủ
  2. » Công Nghệ Thông Tin

Expert VB 2005 Business Objects Second Edition phần 3 doc

69 211 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 69
Dung lượng 1,45 MB

Nội dung

Sometimes, the IsNew property can be useful to the UI developer as well. Some UI behaviors may be different for a new object than an existing object. The ability to edit the object’s primary key data is a good example—this is often editable only up to the point that the data has been stored in the database. When the object becomes “old,” the primary key is fixed. IsDirty An object is considered to be “dirty,” or changed, when the values in the object’s fields do not match the values in the database. If the values in the object’s fields do match the values in the database, then the object is not dirty. It is virtually impossible to always know whether the object’s values match those in the database, so the implementation shown here acts on a “best guess.” The imple- mentation relies on the business developer to indicate when an object has been changed and thus has become dirty. The current status of the value is maintained in a field: Private mIsDirty As Boolean = True The value is then exposed as a property: <Browsable(False)> _ Public Overridable ReadOnly Property IsDirty() As Boolean Get Return mIsDirty End Get End Property Notice that this property is marked as Overridable. This is important because sometimes a business object isn’t simply dirty because its data has changed. For instance, consider a business object that contains a collection of child objects—even if the business object’s data hasn’t changed, it will be dirty if any of its child objects have changed. In this case, the business developer will need to override the IsDirty property to provide a more sophisticated implementation. This will be clearly illustrated in Chapter 7, in the implementation of the example business objects. Also notice that the property is adorned with the <Browsable()> attribute from the System. ComponentModel namespace. This attribute tells data binding not to automatically bind this prop- erty.Without this attribute, data binding would automatically display this property in grids and on forms—and typically, this property shouldn’t be displayed. This attribute is used on other proper- ties in BusinessBase as well. The IsDirty property defaults to True, since a new object’s field values won’t correspond to v alues in the database . I f the object ’s values are subsequently loaded from the database, this value will be changed to False when MarkOld() is called. Remember that MarkOld() calls a MarkClean() method: <EditorBrowsable(EditorBrowsableState.Advanced)> _ Protected Sub MarkClean() mIsDirty = False OnUnknownPropertyChanged() End Sub This method not only sets the value to False, but calls the OnUnknownPropertyChanged() method implemented in Csla.Core.BindableBase to raise the PropertyChanged event for all object properties. This notifies data binding that the object has changed, so Windows Forms can refresh the display for the user . There’s a corresponding MarkDirty() method as well. This method will be called from various points in an object’s lifetime, including any time a property value is changed, or when the MarkNew() method is called. CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION 115 6315_c03_final.qxd 4/13/06 12:29 PM Page 115 When a property value has been changed, a specific PropertyChanged event will be raised for that property. If MarkDirty() is called at other times, when a specific property value wasn’t changed, then the PropertyChanged event for all object properties should be raised. That way, data binding is notified of the change if any object property is bound to a UI control. To be clear, the goal is to ensure that at least one PropertyChanged event is raised any time the o bject’s state changes. If a specific property were changed, then the P ropertyChanged e vent should be raised for that property. But if there’s no way to tell which properties were changed (like when the object is persisted to the database) there’s no real option but to raise PropertyChanged for every property. Implementing this requires a couple of overloads of the MarkDirty() method: Protected Sub MarkDirty() MarkDirty(False) End Sub <EditorBrowsable(EditorBrowsableState.Advanced)> _ Protected Sub MarkDirty(ByVal supressEvent As Boolean) mIsDirty = True If Not supressEvent Then OnUnknownPropertyChanged() End If End Sub The first overload can be called by a business developer if they want to manually mark the object as changed. This is intended for use when unknown properties may have changed. The second o verload is called by the PropertyHasChanged() method: Protected Sub PropertyHasChanged(ByVal propertyName As String) ValidationRules.CheckRules(propertyName) MarkDirty(True) OnPropertyChanged(propertyName) End Sub The PropertyHasChanged() method is called by the business developer to indicate that a specific property has changed. Notice that in this case, any validation rules for the property are checked (the details on this ar e discussed later in the chapter). Then the object is marked as being dirty by raising the PropertyChanged event for the specific property that was changed. ■Tip This method is Overridable, allowing you to add extra steps to the process if needed. Additionally, this means you can override the beha vior to implement field-level dirty tracking if desired. C alling PropertyHasChanged() b y passing the property name as a string value would mean hard-coding the property name in code. String literals are notoriously difficult to maintain, so there’s an overload to automatically glean the property name at runtime: <System.Runtime.CompilerServices.MethodImpl( _ System.Runtime.CompilerServices.MethodImplOptions.NoInlining)> _ Protected Sub PropertyHasChanged() Dim propertyName As String = _ New System.Diagnostics.StackTrace(). _ GetFrame(1).GetMethod.Name.Substring(4) PropertyHasChanged(propertyName) End Sub CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION116 6315_c03_final.qxd 4/13/06 12:29 PM Page 116 This implementation uses System.Diagnostics to retrieve the name of the method or property that called PropertyHasChanged(). The <MethodImpl()> attribute prevents the compiler from merg- ing this code directly into the property itself, since that would confuse the System.Diagnostics call. There is a performance penalty (akin to using reflection) to calling System.Diagnostics like this, but I am usually happy to pay that price to avoid using string literals for property names through a business class. Using this method, a business object’s property will look like this: Public Property Name() As String Get CanReadProperty(True) Return mName End Get Set(ByVal value As String) CanWriteProperty(True) If mName <> value Then mName = value PropertyHasChanged() End If End Set End Property The PropertyHasChanged() call doesn’t require the property name because it is automatically retrieved using System.Diagnostics. If you feel the performance penalty for that approach is too high, you can always hard-code the property name as a parameter to every PropertyHasChanged() method call. Either way, the property’s validation rules are checked, the IsDirty property is set to True, and the appropriate PropertyChanged event is raised. IsValid An object is consider ed to be valid if it has no currently broken validation rules. The Csla. Validation namespace is covered later in the chapter and provides management of the business rules. The IsValid property merely exposes a flag indicating whether the object currently has bro- ken rules or not: <Browsable(False)> _ Public Overridable ReadOnly Property IsValid() As Boolean Get Return ValidationRules.IsValid End Get End Property As with IsDirty, this property is marked with the <Browsable()> attribute so data binding defaults to ignor ing the pr operty. IsSavable An object should only be saved to the database if it is valid and its data has changed. The IsValid property indicates whether the object is valid, and the IsDirty property indicates whether the object’s data has changed. The IsSavable property is a simple helper to combine those two pr oper ties into one: <Browsable(False)> _ Public Overridable ReadOnly Property IsSavable() As Boolean Get Return IsDirty AndAlso IsValid End Get End Property CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION 117 6315_c03_final.qxd 4/13/06 12:29 PM Page 117 The primary purpose for this property is to allow a Windows Forms UI developer to bind the Enabled property of a Save button such that the button is only enabled if the object can be saved. IsDeleted The CSLA .NET framework provides for deferred or immediate deletion of an object. The immedi- a te a pproach directly deletes an object’s data from the database without first loading the object into memory. It requires prior knowledge of the object’s primary key value(s), and is discussed in Chapter 4, as it is directly linked to data access. The deferred approach requires that the object be loaded into memory. The user can then view and manipulate the object’s data, and may decide to delete the object, in which case the object is marked for deletion. The object is not immediately deleted, but rather it is deleted if and when the object is saved to the database. At that time, instead of inserting or updating the object’s data, it is deleted from the database. This approach is particularly useful for child objects in a collection. In such a case, the user may be adding and updating some child objects at the same time as deleting others. All the insert, update, and delete operations occur in a batch when the collection is saved to the database. Whether an object is marked for deletion or not is tracked by the mIsDeleted field and exposed through an IsDeleted property. As with IsDirty, there’s a Protected method to allow the object to be marked for deletion when necessary: Protected Sub MarkDeleted() mIsDeleted = True MarkDirty() End Sub Of course, marking the object as deleted is another way of changing its data, so the MarkDirty() method is called to indicate that the object’s state has been changed. The MarkDeleted() method is called from the Delete() and DeleteChild() methods. The Delete() method is used to mark a non-child object for deferred deletion, while DeleteChild() is called by a parent object (like a collection) to mark the child object for deferred deletion: Public Sub Delete() If Me.IsChild Then Throw New NotSupportedException(My.Resources.ChildDeleteException) End If MarkDeleted() End Sub Friend Sub DeleteChild() If Not Me.IsChild Then Throw New NotSupportedException(My.Resources.NoDeleteRootException) End If MarkDeleted() End Sub Both methods do the same thing: call MarkDelete(). But Delete() is scoped as Public and can only be called if the object is not a child object (a topic covered later in the discussion about parent and child object behaviors). Conversely, DeleteChild() can only be called if the object is a child. Since it is intended for use by BusinessListBase, it is scoped as Friend. CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION118 6315_c03_final.qxd 4/13/06 12:29 PM Page 118 N-Level Undo UndoableBase implements the basic functionality to take snapshots of an object’s data and then perform undo or accept operations using these snapshots. These methods were implemented as Protected methods, so they’re not available for use by code in the UI. The BusinessBase class will implement three standard methods for use by the UI code, as described in Table 3-5. Table 3-5. Object-Editing Methods in BusinessBase Method Description BeginEdit() Initiates editing of the object. Triggers a call to CopyState(). CancelEdit() Indicates that the user wants to undo her recent changes. Triggers a call to UndoChanges(). ApplyEdit() Indicates that the user wants to keep her recent changes. Triggers a call to AcceptChanges(). The System.ComponentModel.IEditableObject interface also ties into n-level undo as well as supporting data binding. This interface is used by Windows Forms data binding to control the edit- ing of objects—specifically, to provide a single level of undo behavior. When using n-level undo, the UI should star t by calling BeginEdit(). If the user then clicks a Cancel button, the CancelEdit() method can be called. If the user clicks a Save or an Accept but- ton, then ApplyEdit() can be called. See Chapter 8 for an example of using n-level undo within a rich Windows Forms UI. Calling BeginEdit() multiple times will cause stacking of states. This allows complex hier- archical interfaces to be created, in which each form has its own Cancel button that triggers a call to CancelEdit(). It is important to recognize that every BeginEdit() call must have a corresponding CancelEdit() or ApplyEdit() call. R efer to the UndoableBase implementation r egarding the use of a Stack object to maintain the list of states. BeginEdit, CancelEdit, and ApplyEdit Methods The basic edit methods are intended for use by UI developers so they can control when an object’s state is tr apped and restored. They delegate the work to the methods in UndoableBase, but include other code to interact appropriately with the IEditableObject implementation: Public Sub BeginEdit() mBindingEdit = True CopyState() End Sub Public Sub CancelEdit() UndoChanges() End Sub Protected Overrides Sub UndoChangesComplete() mBindingEdit = False ValidationRules.SetTarget(Me) AddBusinessRules() OnUnknownPropertyChanged() MyBase.UndoChangesComplete() End Sub CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION 119 6315_c03_final.qxd 4/13/06 12:29 PM Page 119 Public Sub ApplyEdit() mBindingEdit = False mNeverCommitted = False AcceptChanges() End Sub The primary action in each method is to delegate to the corresponding method in UndoableBase. The mBindingEdit and mNeverCommitted fields are used by the implementation of IEditableObject. N otice the overridden U ndoChangesComplete() m ethod. This is required because there are actions that must be taken any time the object’s state has been restored. While it may seem that these actions could be taken in the CancelEdit() method, remember that a business object’s state can also be restored by its parent object through UndoableBase—without ever calling CancelEdit() on the child object. Overriding UndoChangesComplete() means that these lines of code will run after CancelEdit() is either called directly on this object or on its parent object. The code in UndoChangesComplete() sets the mBindingEdit flag, reestablishes the object’s vali- dation rules, and raises the PropertyChanged event for all properties on the object—thus ensuring that data binding is aware that the object’s state has changed. The ValidationRules class will be implemented later in the chapter, but it manages a list of business rules for each property. It also maintains a list of curr ently broken business rules. The list of broken business rules is part of the object’s state and is subject to n-level undo. The list of rules associated with each property is really a list of delegate references, which can be broken by serialization. To prevent any such issues, that list isn’t subject to serialization or n-level undo. Instead, after resetting the object’s state with UndoChanges(), the business rules are simply reassociated with the pr oper ties by calling the AddBusinessRules() method. The SetTarget() method is also called to ensure that ValidationRules has a current reference to the business object. This will be much clearer later in the chapter as you look at the ValidationRules and BrokenRulesCollection classes. System.ComponentModel.IEditableObject The System.ComponentModel.IEditableObject interface is used by the Windows Forms data binding infrastructure to control undo operations in two cases: • If an object is a child of a collection and is being edited in a grid control, the IEditableObject interface will be used so that the user can start editing a row of the grid (that is, the object) and then press Esc to undo any edits he has made on the row. • When binding controls from a Windows Form to an object’s properties, the IEditableObject inter face will be used to tell the object that editing has star ted . I t will not be used to tell the object when editing is complete, or whether the user requests an undo. It’s up to the UI code to handle these cases. When using data binding to bind an object to a form, you can allow the data binding infra- structure to tell the object that editing has started. I typically don’t rely on that feature, preferring to call BeginEdit() myself. S ince I have to call CancelEdit() and ApplyEdit() manually anyway , I prefer simply to control the entire process. ■Note The BeginEdit() and CancelEdit() methods on this interface are different from the Public methods a developer may call directly. The rules for using the interface apply to data binding, and you should not confuse them with the rules for calling BeginEdit(), CancelEdit(), or ApplyEdit() manually. CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION120 6315_c03_final.qxd 4/13/06 12:29 PM Page 120 IEditableObject is most important when an object is being edited within a grid control. In that case, this interface is the only way to get the editing behavior that’s expected by users. Clearly, implementing the interface requires understanding of how it is used. The interface defines three methods, as described in Table 3-6. Table 3-6. IEditableObject Interface Methods Method Description BeginEdit() This is called by data binding to indicate the start of an edit process. However, it may be called by the Windows Forms data binding infrastructure many times during the same edit process, and only the first call should be honored. CancelEdit() This is called by data binding to indicate that any changes since the first BeginEdit() call should be undone. However, it may be called by the Windows Forms data binding infrastructure many times during the same edit process, and only the first call should be honored. EndEdit() This is called by data binding to indicate that the edit process is complete, and that any changes should be kept intact. However, it may be called by the Windows Forms data binding infrastructure many times during the same edit process, and only the first call should be honored. ■Note The official Microsoft documentation on these methods is somewhat inconsistent with their actual behav- ior. In the documentation, only BeginEdit() is noted for being called multiple times, but experience has shown that any of these methods may be called multiple times. While these methods are certainly similar to the edit methods implemented earlier, there ar e some key differences in the way these new methods work. Consider BeginEdit(), for exam - ple. Every call to the existing BeginEdit() method will result in a new snapshot of the object’s state, while only the first call to IEditableObject.BeginEdit() should be honored. Any subse- quent calls (and they do happen during data binding) should be ignored. The same is true for the other two methods. Remember, data binding only uses a single level of undo. By definition, this means that only the first call to BeginEdit() through the IEditableObject interface has any meaning. To implement the behavior of the IEditableObject methods properly, the object needs to keep tr ack of whether the edit process has been started and when it ends. At the same time, though, it is important to preserve the existing BeginEdit() functionality. This means implement- ing separate methods for IEditableObject, which will call the preexisting n-level undo methods when appropriate. There is one other complication to deal with as well. When a collection of objects is bound to a W indows Forms grid control, the user can dynamically add and remove child objects in the collection by using the grid control. When an object is removed in this manner, the grid control does not notify the collection object. Instead, it notifies the child object, and it’s up to the child object to remove itself from the collection. I t is then up to the child to inter act with its par ent collection to be r emoved from the collection itself. F or this to happen, the child object needs a r eference to its parent collection. This is expressed through a Protected property named Parent, which is discussed later in the chapter, in the “Root, Parent, and Child Behaviors” section. A flag is used to ignore multiple calls to the IEditableObject methods: CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION 121 6315_c03_final.qxd 4/13/06 12:29 PM Page 121 <NotUndoable()> _ Private mBindingEdit As Boolean Private mNeverCommitted As Boolean = True Notice that mBindingEdit is declared with the <NotUndoable()> attribute. This field controls interaction with the UI, not internal object state; and because of this, there’s no reason to make it part of the object’s snapshot data, as that would just waste memory. A second flag is also declared, and is used to track whether ApplyEdit() has been called on the object. This value was set to False in the ApplyEdit() implemented earlier, and will be used to con- trol whether a child object should remove itself from its parent collection. The three interface methods are implemented as follows: Private Sub IEditableObject_BeginEdit() _ Implements System.ComponentModel.IEditableObject.BeginEdit If Not mBindingEdit Then BeginEdit() End If End Sub Private Sub IEditableObject_CancelEdit() _ Implements System.ComponentModel.IEditableObject.CancelEdit If mBindingEdit Then CancelEdit() If IsNew AndAlso mNeverCommitted AndAlso _ EditLevel <= EditLevelAdded Then If Not Parent Is Nothing Then Parent.RemoveChild(Me) End If End If End If End Sub Private Sub IEditableObject_EndEdit() _ Implements System.ComponentModel.IEditableObject.EndEdit If mBindingEdit Then ApplyEdit() End If End Sub Notice that the methods are declared using syntax to explicitly implement the IEditableObject interface. This is required because BeginEdit() and CancelEdit() are already public methods in the class , and this avoids any naming conflict. All three methods call the corresponding edit methods implemented earlier . The mBindingEdit field is used to determine whether the BeginEdit() method has been called already so any subsequent method calls can be ignored. The mBindingEdit field is set to True when an edit process is started, and to False when either CancelEdit() or ApplyEdit() is called. The mNeverCommitted field tr acks whether the ApplyEdit() method has ev er been called. If it hasn’t ever been called, and data binding attempts to cancel the edit operation, this flag is used to control whether the object should remove itself from its parent collection. The mNeverCommitted field starts out True and is set to False if ApplyEdit() is called. W ith this mechanism in place , the implementation of IEditableObject.BeginEdit() calls only the real BeginEdit() method if no edit session is currently underway. With the implementa- tion of the n-level undo methods and System.ComponentModel.IEditableObject, business objects now provide full control over editing and undo capabilities, both to the UI developer and to Windows Forms data binding. CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION122 6315_c03_final.qxd 4/13/06 12:29 PM Page 122 Root, Parent, and Child Behaviors Chapter 2 introduced the idea that a business object can be a root, parent, and/or child object. A definition of each can be found in Table 3-7. Table 3-7. Root, Parent, and Child Object Definitions Object Type Definition R oot An object that can be directly retrieved or updated via the data portal Parent An object that contains other business objects as part of its state Child An object that is contained by another business object A root object may be a stand-alone object. It may also be a parent if it contains child objects. A child object could also be a parent if it, in turn, contains other child objects. An example of a root and parent object is an Invoice, while an example of a child object would be a LineItem object within that Invoice. Child objects are related to root objects via a containment relationship, as illustrated by the class diagram in Figure 3-3. MarkAsChild The business programmer makes the choice about whether an object is a child or not through code. By default, an object is a root object, and is only considered to be a child object if the MarkAsChild() method is called in the object ’ s constructor. The MarkAsChild() method looks like this: Protected Sub MarkAsChild() mIsChild = True End Sub The mIsChild field is used to maintain whether the object is a child, and that value is exposed via an IsChild property: CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION 123 Figure 3-3. Class diagr am sho wing ho w root, child, and grandchild objects are related 6315_c03_final.qxd 4/13/06 12:29 PM Page 123 <NotUndoable()> _ Private mIsChild As Boolean Protected Friend ReadOnly Property IsChild() As Boolean Get Return mIsChild End Get End Property Notice that the field is declared using the <NotUndoable()> attribute. Since this value will never change during the lifetime of the object, there’s no reason to include it in an n-level undo snapshot. The IsChild property will be used within other BusinessBase code, and may be useful to the business developer, so it’s declared as Protected. There are certain behaviors that are valid only for root objects, and others that apply only to child objects. These rules will be enforced by throwing exceptions when an invalid operation is attempted. The Delete() and DeleteChild() methods implemented earlier are examples of this appr oach. Parent Property If a business object is a child of a collection, then it will maintain a reference to its parent business object. As you saw earlier, this is required for implementation of System.ComponentModel. IEditableObject . To avoid circular reference issues with n-level undo and serialization, the field holding this refer ence must be declared with the <NotUndoable()> and <NonSerialized()> attr ibutes . Without these attributes, UndoableBase will go into an infinite loop during CopyState(), and .NET seriali- zation will create a much larger byte stream during serialization than is required. The value will also be exposed through a property: <NotUndoable()> _ <NonSerialized()> _ Private mParent As Core.IEditableCollection <EditorBrowsable(EditorBrowsableState.Advanced)> _ Protected ReadOnly Property Parent() As Core.IEditableCollection Get Return mParent End Get End Property Due to the fact that the mParent field is not serializable, its value must be restored by the par- ent collection any time that deserialization occurs. To make this possible, the collection will call a Friend method on the business object: Friend Sub SetParent(ByVal parent As Core.IEditableCollection) If Not IsChild Then Throw New InvalidOperationException(My.Resources.ParentSetException) End If mParent = parent End Sub This method is only valid if the object is a child object, and all it does is store the parent object reference in the mParent field. CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION124 6315_c03_final.qxd 4/13/06 12:29 PM Page 124 [...]... value that includes any custom data that is part of the arguments object When the business developer associates a rule method with a property, ValidationRules creates a RuleMethod object to maintain all this information This RuleMethod object is what’s actually 133 631 5_c 03_ final.qxd 134 4/ 13/ 06 12:29 PM Page 134 CHAPTER 3 s BUSINESS FRAMEWORK IMPLEMENTATION associated with the property, thus providing... the business developer in implementing and enforcing business rules The Csla.Core.BusinessBase class, discussed earlier in the “BusinessBase Class” section, illustrated how some of the functionality in the Csla.Validation namespace will be used This includes managing a list of business rules for each of the object’s properties and maintaining a list of currently broken business rules 131 631 5_c 03_ final.qxd... business developer will use to create editable and read-only business objects and collections: • Csla.BusinessBase(Of T) • Csla.BusinessListBase(Of T, C) • Csla.ReadOnlyBase(Of T) • Csla.ReadOnlyListBase(Of T, C) Let’s walk through each of these in turn BusinessBase Class The Csla.BusinessBase class is the primary base class for creating both editable root and editable child objects This includes objects. .. the data access support that will be added in Chapter 4, the BusinessBase class is now complete BusinessListBase Class While BusinessBase is the primary base class for building business objects, the framework must also support collections of business objects Both the UndoableBase and Csla.Core.BusinessBase classes made accommodations for the BusinessListBase class discussed here Remember the use of Csla... declared like this: _ Public Class LineItems Inherits Csla.BusinessListBase(Of LineItems, LineItem) End Class 631 5_c 03_ final.qxd 4/ 13/ 06 12:29 PM Page 147 CHAPTER 3 s BUSINESS FRAMEWORK IMPLEMENTATION This indicates that the collection contains business objects defined by a LineItem class that inherits from Csla.BusinessBase(Of LineItem) With this basis established, let’s move on and... RuleMethod objects, so it then loops through each list, invoking all the rules The rule is then added or removed from BrokenRulesList based on the result At this point, it should be clear how ValidationRules associates rule methods with properties and is then able to check those rules for a specific property or for the business object as a whole 631 5_c 03_ final.qxd 4/ 13/ 06 12:29 PM Page 137 CHAPTER 3 s BUSINESS. .. _ Public Class BrokenRulesCollection Inherits Core.ReadOnlyBindingList(Of BrokenRule) Friend Sub New() ' limit creation to this assembly End Sub End Class 137 631 5_c 03_ final.qxd 138 4/ 13/ 06 12:29 PM Page 138 CHAPTER 3 s BUSINESS FRAMEWORK IMPLEMENTATION The collection also includes a Friend constructor, thus ensuring that an instance of the object can only be created from within the CSLA... to all event handlers Business rules aren’t event handlers, so RuleArgs doesn’t inherit from EventArgs, but it follows the same basic principal: Public Class RuleArgs Private mPropertyName As String Private mDescription As String Public ReadOnly Property PropertyName() As String Get Return mPropertyName End Get End Property 631 5_c 03_ final.qxd 4/ 13/ 06 12:29 PM Page 133 CHAPTER 3 s BUSINESS FRAMEWORK IMPLEMENTATION... Inherits Core.BusinessBase End Class The use of generics here is a bit tricky The type parameter, T, is constrained to only allow types that inherit from BusinessBase(Of T) This is a self-referencing generic and ensures that BusinessBase(Of T) can only be used as a base class when the subclass itself is provided as T For instance, a business class looks like this: 1 43 631 5_c 03_ final.qxd 144 4/ 13/ 06 12:29... 631 5_c 03_ final.qxd 4/ 13/ 06 12:29 PM Page 125 CHAPTER 3 s BUSINESS FRAMEWORK IMPLEMENTATION Edit Level Tracking for Child Objects N-level undo of collections of child objects is pretty complex, a fact that will become clear in the implementation of BusinessListBase The biggest of several problems arises when a new child object . property: CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION 1 23 Figure 3- 3. Class diagr am sho wing ho w root, child, and grandchild objects are related 631 5_c 03_ final.qxd 4/ 13/ 06 12:29 PM Page 1 23 <NotUndoable()>. This RuleMethod object is what ’ s actually CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION 133 631 5_c 03_ final.qxd 4/ 13/ 06 12:29 PM Page 133 associated with the property, thus providing all the. of business rules for each of the object’s properties and maintaining a list of curr ently br oken business r ules . CHAPTER 3 ■ BUSINESS FRAMEWORK IMPLEMENTATION 131 631 5_c 03_ final.qxd 4/ 13/ 06

Ngày đăng: 12/08/2014, 16:21