Morten Mertner
Senior Consultant, Teknologisk Institut
[email protected] / [email protected]
Architect and Software Developer
Instructor
Speaker (conferences and gatherings)
MCSD.NET, MCT
Open Source
- Gentle.NET (object persistence framework / object-relational mapper) - MbUnit (unit test framework)
Agenda
Data Binding - Concepts - Interfaces Demonstration - Gentle 2.0- Data Binding with Windows Forms 2.0 (Brian Noyes)
Concepts – Data Binding
What is data binding?
- semi-automatic transfer of object state
- synchronized state between multiple objects
- easy wiring between UI controls and data/business objects
Why do we need it?
- productivity (less code to write, maintain and understand) - reduced complexity
- intuitive programming model - consistent results
Concepts – Types of Data Binding
Simple data binding - single value
Complex data binding - multiple values - collections
Data binding information
- direction (one-way or two-way) - timing (when is data transferred)
Concepts – Data Binding ”roles”
Entity
- single object
Collection
- container class for storing entities
Control
Interfaces
How it works
- we enable support for data binding by implementing interfaces - most are optional
- functionality/behavior depends on which interfaces we implement
Implementation
- interfaces for entities - interfaces for collections - interfaces for controls
Interfaces – Entities
IEditableObject
INotifyPropertyChanged
IDataErrorInfo
Interfaces – IEditableObject
Purpose
- support for transactional editing of objects (deferring commit until editing is completed)
- entities should maintain internal object state (new or dirty)
- allows validation to use final state rather than individual values - use when object has co-dependent properties
Implementation Effort
- code can be placed in base class - low effort
Interfaces – INotifyPropertyChanged
Purpose
- notify a container class when a property changes (this allows the list to raise a ListChanged event)
- performance optimization (less use of reflection by collection class) - flexibility (other code may benefit from events as well)
- semi-optional (collection can implement IRaiseItemChangedEvents instead, providing slightly less functionality)
Implementation Effort
- an event must be raised whenever a property is modified - code is difficult to put in base class (affects all properties) - high effort
Interfaces – IDataErrorInfo
Purpose
- support for storing and exposing error information - exposes a top-level error (for the entire object)
- exposes individual errors (for each property) using an indexer - can be used by controls (e.g. DataGridView) to highlight errors
Implementation Effort
- code can be placed in base blass
- validation is obviously custom code (but not specific to data binding) - low effort (excl. validation code)
Interfaces – ICustomTypeDescriptor
Purpose
- allows an object to provide custom property information - increase performance (by avoiding reflection)
- increase flexibility (by customizing which properties are exposed) - optional (unless you want to hide properties, etc.)
Implementation Effort
- code can be placed in base class
- code may require additional helper classes (e.g. attributes) - medium effort
Interfaces – Collections
IEnumerable<T> IEnumerator<T> ICollection<T> IList<T> IListSource ITypedList IBindingList<T> IBindingListView ICancelAddNewInterfaces – IEnumerable<T> (and IEnumerator<T>)
Purpose
- enable iteration of items in collection
- helper class allows for more than one iteration strategy
- support for one-way data binding when used with BindingSource
Implementation Effort
- code can be placed in base collection class - easy to implement
Interfaces – ICollection<T>
Purpose
- enable direct access to items in a collection - modify the collection (add/remove items)
- count items, copy to array, synchronization/locking - extends IEnumerable<T>
Implementation Effort
- code can be placed in base collection class - easy to implement
Interfaces – IList<T>
Purpose
- enable positional access to items in a collection (indexing) - support for complex data binding
- extends ICollection<T>
Implementation Effort
- code can be placed in base collection class - easy to implement
Interfaces – IListSource
Purpose
- find out whether a collection contain entities or other collections - select the default collection for data binding
- obtain a collection for data binding from objects that are not collections
Implementation Effort
- code can be placed in base class (when using reflection) - easy to implement
Interfaces – ITypedList
Purpose
- expose information on properties of the data binding source (entities) - allows for great flexibility
- information is exposed using the PropertyDescriptor class
Implementation Effort
- can be placed in base collection class - fairly easy to implement
Interfaces – IBindingList<T>
Purpose
- support for full-featured data binding - sorting
- searching
- control changes to the collection (allow new/edit/remove) - change notifications (events)
Implementation Effort
- can be implemented in base collection class - medium effort
Interfaces – IBindingListView
Purpose
- support for advanced (multi-property) sorting - support for filtering
- allows a custom collection to do the same as DataView
Implementation Effort
- can be implemented in base collection class - medium effort
Interfaces – ICancelAddNew
Purpose
- support for “transactional” adding or editing of items
- allows collection class to handle cancellation of operation
(removes the coupling otherwise needed between entity and collection)
Implementation Effort
- can be implemented in base collection class - low effort
Interfaces – IRaiseItemChangedEvents
Purpose
- collection will notify when property changes on contained items
- only works for changes made through PropertyDescriptor class (UI) - use when contained items do not implement INotifyPropertyChanged
Implementation Effort
- can be implemented in base collection class - low effort
Interfaces – Controls
ISupportInitialize
ISupportInitializeNotification
Interfaces – ISupportInitialize
Purpose
- allows a control to wait until all changes (to a data-bound object) have been committed
- allows a control to remain ignorant of co-dependent properties
Implementation Effort
- code can be placed in base control - low effort
Interfaces – ISupportInitializeNotification
Purpose
- notification of interdependent objects when initialization is complete - allows for complex initialization scenarios
Implementation Effort - low effort
Interfaces – ICurrencyManagerProvider
Purpose
- lets a control provide its own currency manager - implemented by BindingSource
- you should not implement this interface (but might use it to access the CurrencyManager for a data-bound collection within a control)
Implementation Effort - not required
Demonstration
Gentle 2.0
- Entity base class
- ListBase<TEntity> collection class - Sample project
Demonstration
Entity base class for (persistent) business objects
Data binding interfaces
- INotifyPropertyChanged (raise events when properties are modified) - IEditableObject (event handlers for data binding events)
- IDataErrorInfo (error tracking)
Custom interfaces
- IEntity (object identity and persistency state)
Demonstration
ListBase<TEntity> collection class - inherits from BindingList<T>
Data binding interfaces - BindingList<T> - IBindingListView
- IRaiseItemChangedEvents - ITypedList
Conclusion
IList is the minimum requirement
- BindingSource transforms an IEnumerable to an IList
IBindingList should be the minimum for collections
- IBindingListView adds advanced functionality known from DataView
INotifyPropertyChanged is important for rich data-binding (also detects programmatic changes to properties)
PropertyDescriptor class is the mediator between properties and controls, and is used when a value is modified through the UI)