9using System.Collections.Generic;
10using System.ComponentModel;
11using System.Windows.Forms;
23 [ProvideProperty(
"ActionType", typeof (Control))]
24 [ProvideProperty(
"PostSaveAction", typeof (Control))]
25 [ProvideProperty(
"RebindAfterSave", typeof (Control))]
26 [ProvideProperty(
"DisableWhenClean", typeof (Control))]
27 [ProvideProperty(
"DisableWhenUseless", typeof (Control))]
28 [ProvideProperty(
"CommandName", typeof (Control))]
39 _container = container;
45 #region Member variables
47 private Dictionary<Control, CslaActionExtenderProperties> _sources =
48 new Dictionary<Control, CslaActionExtenderProperties>();
50 private object _dataSource =
null;
51 private bool _autoShowBrokenRules =
true;
52 private bool _warnIfCloseOnDirty =
true;
54 private bool _warnOnCancel =
false;
57 private IContainer _container =
null;
59 private bool _closeForm =
false;
63 #region IExtenderProvider implementation
65 bool IExtenderProvider.CanExtend(
object extendee)
67 return extendee is IButtonControl;
72 #region Public properties
78 [Description(
"Gets or sets the data source to which this button is bound for action purposes.")]
79 [AttributeProvider(typeof (IListSource))]
82 get {
return _dataSource; }
87 if (value is BindingSource)
99 [Category(
"Behavior")]
100 [Description(
"If True, then the broken rules will be displayed in a message box, should the object be invalid.")]
105 get {
return _autoShowBrokenRules; }
106 set { _autoShowBrokenRules = value; }
113 [Category(
"Behavior")]
114 [Description(
"If True, then the control (when set to Close mode) will warn the user if the object is currently dirty.")]
119 get {
return _warnIfCloseOnDirty; }
120 set { _warnIfCloseOnDirty = value; }
127 [Category(
"Behavior")]
128 [Description(
"Gets or sets the confirmation message that will display if a Close button is pressed and the object is dirty.")]
130 [DefaultValue(
"Object is currently in a dirty changed.")]
134 get {
return _dirtyWarningMessage; }
135 set { _dirtyWarningMessage = value; }
142 [Category(
"Behavior")]
143 [Description(
"If True, then the Cancel button will warn when pressed and the object is dirty.")]
145 [DefaultValue(
false)]
148 get {
return _warnOnCancel; }
149 set { _warnOnCancel = value; }
156 [Category(
"Behavior")]
157 [Description(
"If the WarnOnCancel property is set to True, this is the message to be displayed.")]
159 [DefaultValue(
"Are you sure you want to revert to the previous values?")]
163 get {
return _warnOnCancelMessage; }
164 set { _warnOnCancelMessage = value; }
171 [Category(
"Behavior")]
172 [Description(
"When a button with a Validate ActionType is pressed when the object is valid, this is the message to be displayed.")]
174 [DefaultValue(
"Object is valid.")]
178 get {
return _objectIsValidMessage; }
179 set { _objectIsValidMessage = value; }
184 #region Property accessor methods
194 [Description(
"Gets or sets the action type for this button.")]
199 if (_sources.ContainsKey(ctl))
200 return _sources[ctl].ActionType;
202 return CslaActionExtenderProperties.ActionTypeDefault;
211 [Description(
"Gets or sets the action type for this button.")]
216 if (_sources.ContainsKey(ctl))
217 _sources[ctl].ActionType = value;
220 CslaActionExtenderProperties props =
new CslaActionExtenderProperties();
221 props.ActionType = value;
222 _sources.Add(ctl, props);
228 #region PostSaveAction
236 [Description(
"Gets or sets the action performed after a save (if ActionType is set to Save).")]
241 if (_sources.ContainsKey(ctl))
242 return _sources[ctl].PostSaveAction;
244 return CslaActionExtenderProperties.PostSaveActionDefault;
253 [Description(
"Gets or sets the action performed after a save (if ActionType is set to Save).")]
258 if (_sources.ContainsKey(ctl))
259 _sources[ctl].PostSaveAction = value;
262 CslaActionExtenderProperties props =
new CslaActionExtenderProperties();
263 props.PostSaveAction = value;
264 _sources.Add(ctl, props);
270 #region RebindAfterSave
277 [Description(
"Determines if the binding source will rebind after business object saves.")]
282 if (_sources.ContainsKey(ctl))
283 return _sources[ctl].RebindAfterSave;
285 return CslaActionExtenderProperties.RebindAfterSaveDefault;
294 [Description(
"Determines if the binding source will rebind after business object saves.")]
299 if (_sources.ContainsKey(ctl))
300 _sources[ctl].RebindAfterSave = value;
303 CslaActionExtenderProperties props =
new CslaActionExtenderProperties();
304 props.RebindAfterSave = value;
305 _sources.Add(ctl, props);
311 #region DisableWhenUseless
318 [Description(
"If True, then the status of the underlying business object will cause this button to be enabled or disabled.")]
320 [DefaultValue(
false)]
323 if (_sources.ContainsKey(ctl))
324 return _sources[ctl].DisableWhenUseless;
326 return CslaActionExtenderProperties.DisableWhenUselessDefault;
335 [Description(
"If True, then the status of the underlying business object will cause this button to be enabled or disabled.")]
340 if (_sources.ContainsKey(ctl))
341 _sources[ctl].DisableWhenUseless = value;
344 CslaActionExtenderProperties props =
new CslaActionExtenderProperties();
345 props.DisableWhenUseless = value;
346 _sources.Add(ctl, props);
359 [Description(
"Gets or sets the name of this command control for unique identification purposes.")]
364 if (_sources.ContainsKey(ctl))
365 return _sources[ctl].CommandName;
367 return CslaActionExtenderProperties.CommandNameDefault;
376 [Description(
"Gets or sets the name of this command control for unique identification purposes.")]
381 if (_sources.ContainsKey(ctl))
382 _sources[ctl].CommandName = value;
385 CslaActionExtenderProperties props =
new CslaActionExtenderProperties();
386 props.CommandName = value;
387 _sources.Add(ctl, props);
395 #region Event declarations
401 [Description(
"Event fires just before the attempted action.")]
402 public event EventHandler<CslaActionCancelEventArgs>
Clicking;
408 [Description(
"Event fires after a successful action. When button is set to Save, this event will only fire upon a successful save. If button is set to Close, this event will never fire.")]
409 public event EventHandler<CslaActionEventArgs>
Clicked;
415 [Description(
"Event fires upon encountering any exception during an action.")]
422 [Description(
"Event fires upon a successful save when the PostSaveAction property is set to AndNew.")]
423 public event EventHandler<CslaActionEventArgs>
SetForNew;
429 [Description(
"Event fires when the object is in an invalid state. Note that this event will work in conjunction with the InvalidateOnWarnings and InvalidateOnInformation properties.")]
436 [Description(
"Event fires if there are any broken rules at all, despite severity.")]
443 [Description(
"Fires just before a save action is performed.")]
450 [Description(
"Fires immediately after the underlying object successfully saves.")]
455 #region OnEvent methods
539 #region Public methods
547 InitializeControls(
true);
549 BindingSource rootSource = _dataSource as BindingSource;
551 if (rootSource !=
null)
553 AddEventHooks(objectToBind);
556 _bindingSourceTree = BindingSourceHelper.InitializeBindingSourceTree(_container, rootSource);
557 _bindingSourceTree.
Bind(objectToBind);
560 private void AddEventHooks(
ISavable objectToBind)
563 RemoveEventHooks(objectToBind);
565 INotifyPropertyChanged propChangedObjParent = objectToBind as INotifyPropertyChanged;
566 if (propChangedObjParent !=
null)
568 propChangedObjParent.PropertyChanged += propChangedObj_PropertyChanged;
572 if (propChangedObjChild !=
null)
574 propChangedObjChild.
ChildChanged += propChangedObj_ChildChanged;
578 private void RemoveEventHooks(
ISavable objectToBind)
580 INotifyPropertyChanged propChangedObjParent = objectToBind as INotifyPropertyChanged;
581 if (propChangedObjParent !=
null)
583 propChangedObjParent.PropertyChanged -= propChangedObj_PropertyChanged;
587 if (propChangedObjChild !=
null)
589 propChangedObjChild.
ChildChanged -= propChangedObj_ChildChanged;
598 private void propChangedObj_PropertyChanged(
object sender, PropertyChangedEventArgs e)
605 #region Protected methods
612 protected void OnClick(
object sender, EventArgs e)
614 Control ctl = (Control) sender;
615 CslaActionExtenderProperties props = _sources[ctl];
620 bool raiseClicked =
true;
627 BindingSource source =
null;
629 var sourceObjectError =
false;
630 if (_dataSource !=
null)
632 source = _dataSource as BindingSource;
636 savableObject = source.DataSource as
ISavable;
642 sourceObjectError =
true;
645 if (savableObject ==
null || trackableObject ==
null)
648 sourceObjectError =
true;
652 if (!sourceObjectError)
654 DialogResult diagResult;
656 switch (props.ActionType)
659 raiseClicked = ExecuteSaveAction(savableObject, trackableObject, props);
665 diagResult = DialogResult.Yes;
666 if (_warnOnCancel && trackableObject.
IsDirty)
667 diagResult = MessageBox.Show(
669 MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
671 if (diagResult == DialogResult.Yes)
672 _bindingSourceTree.
Cancel(savableObject);
679 diagResult = DialogResult.Yes;
682 if (_warnIfCloseOnDirty)
683 diagResult = MessageBox.Show(
688 if (diagResult == DialogResult.Yes)
690 _bindingSourceTree.
Close();
704 string brokenRules =
string.Empty;
707 var lambdaBrokenRule = brokenRule;
709 PropertyInfoManager.GetRegisteredProperties(businessObject.GetType()).Find(
710 c => c.Name == lambdaBrokenRule.Property).FriendlyName;
711 brokenRules +=
string.Format(
"{0}: {1}{2}", friendlyName, brokenRule, Environment.NewLine);
714 MessageBoxButtons.OK, MessageBoxIcon.Error);
719 MessageBoxButtons.OK, MessageBoxIcon.Information);
734 if (props.RebindAfterSave)
738 _bindingSourceTree.ResetBindings(
false);
739 InitializeControls(
true);
745 InitializeControls(
true);
767 #region Private methods
769 private bool ExecuteSaveAction(
ISavable savableObject,
ITrackStatus trackableObject, CslaActionExtenderProperties props)
772 bool okToContinue =
true;
775 bool savableObjectIsBusinessBase = savableObject is
BusinessBase;
776 if (savableObjectIsBusinessBase)
779 if (savableObjectIsBusinessBase)
788 _autoShowBrokenRules);
792 okToContinue = !argsHasBrokenRules.Cancel;
800 if (savableObjectIsBusinessBase)
802 if (_autoShowBrokenRules && !businessObject.
IsValid)
804 string brokenRules =
string.Empty;
807 var lambdaBrokenRule = brokenRule;
809 PropertyInfoManager.GetRegisteredProperties(businessObject.GetType()).Find(
810 c => c.Name == lambdaBrokenRule.Property).FriendlyName;
811 brokenRules +=
string.Format(
"{0}: {1}{2}", friendlyName, brokenRule, Environment.NewLine);
814 MessageBoxButtons.OK, MessageBoxIcon.Error);
820 CslaActionCancelEventArgs savingArgs =
new CslaActionCancelEventArgs(
false, props.CommandName);
823 if (!savingArgs.Cancel)
825 _bindingSourceTree.
Apply();
829 objectToSave = ((ICloneable)savableObject).Clone() as
ISavable;
831 objectToSave = savableObject;
833 if (objectToSave !=
null)
837 RemoveEventHooks(savableObject);
842 switch (props.PostSaveAction)
846 if (props.RebindAfterSave)
848 _bindingSourceTree.
Bind(savableObject);
849 AddEventHooks(savableObject);
860 OnSetForNew(
new CslaActionEventArgs(props.CommandName));
861 AddEventHooks(savableObject);
867 _bindingSourceTree.
Bind(objectToSave);
868 AddEventHooks(objectToSave);
869 OnErrorEncountered(
new ErrorEncounteredEventArgs(props.CommandName,
new ObjectSaveException(ex)));
880 _bindingSourceTree.SetEvents(
true);
899 private void ResetControls()
901 InitializeControls(
false);
904 private void InitializeControls(
bool initialEnabling)
907 List<Control> extendedControls =
new List<Control>();
908 foreach (KeyValuePair<Control, CslaActionExtenderProperties> pair
in _sources)
912 Control ctl = pair.Key;
915 if (pair.Value.DisableWhenUseless || pair.Value.DisableWhenClean)
916 ChangeEnabled(ctl, !(pair.Value.DisableWhenUseless || pair.Value.DisableWhenClean));
920 InitializeControl(ctl, pair);
921 extendedControls.Add(ctl);
926 private void InitializeControl(Control ctl, KeyValuePair<Control, CslaActionExtenderProperties> pair)
928 if (pair.Value.DisableWhenUseless || (pair.Value.DisableWhenClean && !ctl.Enabled))
930 ISavable businessObject = GetBusinessObject();
931 if (businessObject !=
null)
934 if (trackableObject !=
null)
936 if (pair.Value.ActionType ==
CslaFormAction.Cancel || pair.Value.DisableWhenClean)
946 private void ChangeEnabled(Control ctl,
bool newEnabled)
949 if (ctl.Enabled != newEnabled)
950 ctl.Enabled = newEnabled;
953 private void CloseForm()
955 if (_sources.Count > 0)
957 Dictionary<Control, CslaActionExtenderProperties>.Enumerator enumerator = _sources.GetEnumerator();
958 if (enumerator.MoveNext())
960 Control ctl = enumerator.Current.Key;
961 Form frm = GetParentForm(ctl);
968 private Form GetParentForm(Control thisControl)
972 if (thisControl.Parent is Form)
973 frm = (Form) thisControl.Parent;
975 frm = GetParentForm(thisControl.Parent);
980 private ISavable GetBusinessObject()
983 BindingSource source = _dataSource as BindingSource;
985 businessObject = source.DataSource as
ISavable;
987 return businessObject;
Provides consistent context information between the client and server DataPortal objects.
static bool AutoCloneOnUpdate
Gets a value indicating whether objects should be automatically cloned by the data portal Update() me...
This is the base class from which most business objects will be derived.
virtual bool IsValid
Returns true if the object and its child objects are currently valid, false if the object or any of i...
BrokenRulesCollection GetBrokenRules()
Gets the broken rules for this object
Contains event data about the changed child object.
A strongly-typed resource class, for looking up localized strings, etc.
static string ActionExtenderInvalidBindingSourceCast
Looks up a localized string similar to DataSource does not cast to a BindingSource.
static string ActionExtenderErrorCaption
Looks up a localized string similar to Error.
static string ActionExtenderSourceMustBeBindingSource
Looks up a localized string similar to DataSource must be a BindingSource control instance.
static string ActionExtenderWarnOnCancelMessagePropertyDefault
Looks up a localized string similar to Are you sure you want to revert to the previous values?...
static string ActionExtenderCloseConfirmation
Looks up a localized string similar to Are you sure you want to close?.
static string ActionExtenderObjectIsValidMessagePropertyDefault
Looks up a localized string similar to Object is valid.
static string Warning
Looks up a localized string similar to Warning.
static string ActionExtenderInformationCaption
Looks up a localized string similar to Information.
static string ActionExtenderDirtyWarningMessagePropertyDefault
Looks up a localized string similar to Object is currently in a dirty changed.
static string ActionExtenderInvalidBusinessObjectBaseCast
Looks up a localized string similar to The underlying data source does not cast to a CSLA BusinessBas...
Maintains a reference to a BindingSource object on the form.
void Close()
Disconnects from the BindingSource object.
void Apply()
Applies changes to the business object.
void Cancel(object businessObject)
Cancels changes to the business object.
void Bind(object objectToBind)
Binds a business object to the BindingSource.
Event args providing information about a canceled action.
Event args for an action.
Extender control providing automation around data binding to CSLA .NET business objects.
void SetActionType(Control ctl, CslaFormAction value)
Sets the action type.
virtual void OnErrorEncountered(ErrorEncounteredEventArgs e)
Raises the ErrorEncountered event.
EventHandler< CslaActionEventArgs > Clicked
Event indicating the user clicked on the Control.
string GetCommandName(Control ctl)
Gets the command name value.
string ObjectIsValidMessage
Gets or sets the message shown to the user when a button with a Validate ActionType is pressed when t...
virtual void OnObjectSaving(CslaActionCancelEventArgs e)
Raises the ObjectSaving event.
virtual void OnSetForNew(CslaActionEventArgs e)
Raises the SetForNew event.
void SetRebindAfterSave(Control ctl, bool value)
Sets the rebind after save value.
EventHandler< ErrorEncounteredEventArgs > ErrorEncountered
Event indicating an error was encountered.
bool AutoShowBrokenRules
Gets or sets a value indicating whether to automatically show broken rules.
string DirtyWarningMessage
Gets or sets the message shown to the user in a close on dirty warning.
CslaActionExtender(IContainer container)
Creates an instance of the type.
void OnClick(object sender, EventArgs e)
Method invoked when the target control is clicked.
virtual void OnObjectSaved(CslaActionEventArgs e)
Raises the ObjectSaved event.
bool WarnIfCloseOnDirty
Gets or sets a value indicating whether to warn the user on close when the object is dirty.
bool GetRebindAfterSave(Control ctl)
Gets the rebind after save value.
bool GetDisableWhenUseless(Control ctl)
Gets the disable when useless value.
string WarnOnCancelMessage
Gets or sets the message shown to the user in a warn on cancel.
CslaFormAction GetActionType(Control ctl)
Gets the action type.
EventHandler< CslaActionEventArgs > BusinessObjectInvalid
Event indicating the business object is in an invalid state.
PostSaveActionType GetPostSaveAction(Control ctl)
Gets the post save action.
virtual void OnHasBrokenRules(HasBrokenRulesEventArgs e)
Raises the HasBrokenRules event.
EventHandler< CslaActionCancelEventArgs > ObjectSaving
Event indicating that the object is saving.
EventHandler< CslaActionEventArgs > ObjectSaved
Event indicating that the object has been saved.
virtual void OnBusinessObjectInvalid(CslaActionEventArgs e)
Raises the BusinessObjectInvalid event.
virtual void OnClicked(CslaActionEventArgs e)
Raises the Clicked event.
void ResetActionBehaviors(ISavable objectToBind)
Resets all action behaviors.
virtual void OnClicking(CslaActionCancelEventArgs e)
Raises the Clicking event.
void SetCommandName(Control ctl, string value)
Sets the command name value.
EventHandler< CslaActionCancelEventArgs > Clicking
Event indicating the user is clicking on the Control.
EventHandler< CslaActionEventArgs > SetForNew
Event indicating the object is set for new.
object DataSource
Gets or sets a reference to the data source object.
bool WarnOnCancel
Gets or sets a value indicating whether to warn the user on cancel.
void SetDisableWhenUseless(Control ctl, bool value)
Sets the disable when useless value.
void SetPostSaveAction(Control ctl, PostSaveActionType value)
Sets the post save action.
EventHandler< HasBrokenRulesEventArgs > HasBrokenRules
Event indicating the business object has broken rules.
Event args indicating an error.
Event args object containing information about a broken rule.
bool AutoShowBrokenRules
Gets a value indicating whether to show broken rules.
Implemented by classes that notify when a child object has changed.
EventHandler< ChildChangedEventArgs > ChildChanged
Event indictating that a child object has changed.
Specifies that the object can save itself.
object Save()
Saves the object to the database.
Defines the common properties required objects that track their own status.
bool IsDeleted
Returns true if this object is marked for deletion.
bool IsNew
Returns true if this is a new object, false if it is a pre-existing object.
bool IsValid
Returns true if the object and its child objects are currently valid, false if the object or any of i...
bool IsDirty
Returns true if this object's data, or any of its fields or child objects data, has been changed.
CslaFormAction
The possible form actions.
PostSaveActionType
The possible actions for post save.