CSLA.NET 5.4.2
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
CslaActionExtender.cs
Go to the documentation of this file.
1//-----------------------------------------------------------------------
2// <copyright file="CslaActionExtender.cs" company="Marimer LLC">
3// Copyright (c) Marimer LLC. All rights reserved.
4// Website: https://cslanet.com
5// </copyright>
6// <summary>Extender control providing automation around</summary>
7//-----------------------------------------------------------------------
8using System;
9using System.Collections.Generic;
10using System.ComponentModel;
11using System.Windows.Forms;
12using Csla.Core;
14using Csla.Properties;
15
16namespace Csla.Windows
17{
22 [ToolboxItem(true)]
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))]
29 public class CslaActionExtender : Component, IExtenderProvider
30 {
31 #region Constructors
32
37 public CslaActionExtender(IContainer container)
38 {
39 _container = container;
40 container.Add(this);
41 }
42
43 #endregion
44
45 #region Member variables
46
47 private Dictionary<Control, CslaActionExtenderProperties> _sources =
48 new Dictionary<Control, CslaActionExtenderProperties>();
49
50 private object _dataSource = null;
51 private bool _autoShowBrokenRules = true;
52 private bool _warnIfCloseOnDirty = true;
53 private string _dirtyWarningMessage = Resources.ActionExtenderDirtyWarningMessagePropertyDefault;
54 private bool _warnOnCancel = false;
55 private string _warnOnCancelMessage = Resources.ActionExtenderWarnOnCancelMessagePropertyDefault;
56 private string _objectIsValidMessage = Resources.ActionExtenderObjectIsValidMessagePropertyDefault;
57 private IContainer _container = null;
58 private BindingSourceNode _bindingSourceTree = null;
59 private bool _closeForm = false;
60
61 #endregion
62
63 #region IExtenderProvider implementation
64
65 bool IExtenderProvider.CanExtend(object extendee)
66 {
67 return extendee is IButtonControl;
68 }
69
70 #endregion
71
72 #region Public properties
73
77 [Category("Data")]
78 [Description("Gets or sets the data source to which this button is bound for action purposes.")]
79 [AttributeProvider(typeof (IListSource))]
80 public object DataSource
81 {
82 get { return _dataSource; }
83 set
84 {
85 if (value != null)
86 {
87 if (value is BindingSource)
88 _dataSource = value;
89 else
90 throw new ArgumentException(Resources.ActionExtenderSourceMustBeBindingSource);
91 }
92 }
93 }
94
99 [Category("Behavior")]
100 [Description("If True, then the broken rules will be displayed in a message box, should the object be invalid.")]
101 [Bindable(true)]
102 [DefaultValue(true)]
104 {
105 get { return _autoShowBrokenRules; }
106 set { _autoShowBrokenRules = value; }
107 }
108
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.")]
115 [Bindable(true)]
116 [DefaultValue(true)]
118 {
119 get { return _warnIfCloseOnDirty; }
120 set { _warnIfCloseOnDirty = value; }
121 }
122
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.")]
129 [Bindable(true)]
130 [DefaultValue("Object is currently in a dirty changed.")]
131 [Localizable(true)]
133 {
134 get { return _dirtyWarningMessage; }
135 set { _dirtyWarningMessage = value; }
136 }
137
142 [Category("Behavior")]
143 [Description("If True, then the Cancel button will warn when pressed and the object is dirty.")]
144 [Bindable(true)]
145 [DefaultValue(false)]
146 public bool WarnOnCancel
147 {
148 get { return _warnOnCancel; }
149 set { _warnOnCancel = value; }
150 }
151
156 [Category("Behavior")]
157 [Description("If the WarnOnCancel property is set to True, this is the message to be displayed.")]
158 [Bindable(true)]
159 [DefaultValue("Are you sure you want to revert to the previous values?")]
160 [Localizable(true)]
162 {
163 get { return _warnOnCancelMessage; }
164 set { _warnOnCancelMessage = value; }
165 }
166
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.")]
173 [Bindable(true)]
174 [DefaultValue("Object is valid.")]
175 [Localizable(true)]
177 {
178 get { return _objectIsValidMessage; }
179 set { _objectIsValidMessage = value; }
180 }
181
182 #endregion
183
184 #region Property accessor methods
185
186 #region ActionType
187
193 [Category("Csla")]
194 [Description("Gets or sets the action type for this button.")]
195 [Bindable(true)]
196 [DefaultValue(CslaFormAction.None)]
197 public CslaFormAction GetActionType(Control ctl)
198 {
199 if (_sources.ContainsKey(ctl))
200 return _sources[ctl].ActionType;
201
202 return CslaActionExtenderProperties.ActionTypeDefault;
203 }
204
210 [Category("Csla")]
211 [Description("Gets or sets the action type for this button.")]
212 [Bindable(true)]
213 [DefaultValue(CslaFormAction.None)]
214 public void SetActionType(Control ctl, CslaFormAction value)
215 {
216 if (_sources.ContainsKey(ctl))
217 _sources[ctl].ActionType = value;
218 else
219 {
220 CslaActionExtenderProperties props = new CslaActionExtenderProperties();
221 props.ActionType = value;
222 _sources.Add(ctl, props);
223 }
224 }
225
226 #endregion
227
228 #region PostSaveAction
229
235 [Category("Csla")]
236 [Description("Gets or sets the action performed after a save (if ActionType is set to Save).")]
237 [Bindable(true)]
238 [DefaultValue(PostSaveActionType.None)]
240 {
241 if (_sources.ContainsKey(ctl))
242 return _sources[ctl].PostSaveAction;
243
244 return CslaActionExtenderProperties.PostSaveActionDefault;
245 }
246
252 [Category("Csla")]
253 [Description("Gets or sets the action performed after a save (if ActionType is set to Save).")]
254 [Bindable(true)]
255 [DefaultValue(PostSaveActionType.None)]
256 public void SetPostSaveAction(Control ctl, PostSaveActionType value)
257 {
258 if (_sources.ContainsKey(ctl))
259 _sources[ctl].PostSaveAction = value;
260 else
261 {
262 CslaActionExtenderProperties props = new CslaActionExtenderProperties();
263 props.PostSaveAction = value;
264 _sources.Add(ctl, props);
265 }
266 }
267
268 #endregion
269
270 #region RebindAfterSave
271
276 [Category("Csla")]
277 [Description("Determines if the binding source will rebind after business object saves.")]
278 [Bindable(true)]
279 [DefaultValue(true)]
280 public bool GetRebindAfterSave(Control ctl)
281 {
282 if (_sources.ContainsKey(ctl))
283 return _sources[ctl].RebindAfterSave;
284
285 return CslaActionExtenderProperties.RebindAfterSaveDefault;
286 }
287
293 [Category("Csla")]
294 [Description("Determines if the binding source will rebind after business object saves.")]
295 [Bindable(true)]
296 [DefaultValue(true)]
297 public void SetRebindAfterSave(Control ctl, bool value)
298 {
299 if (_sources.ContainsKey(ctl))
300 _sources[ctl].RebindAfterSave = value;
301 else
302 {
303 CslaActionExtenderProperties props = new CslaActionExtenderProperties();
304 props.RebindAfterSave = value;
305 _sources.Add(ctl, props);
306 }
307 }
308
309 #endregion
310
311 #region DisableWhenClean
312
317 [Category("Csla")]
318 [Description("If True, then the dirtiness of the underlying business object will cause this button to be enabled or disabled.")]
319 [Bindable(true)]
320 [DefaultValue(false)]
321 [Obsolete("Use instead DisableWhenUseless")]
322 [Browsable(false)]
323 public bool GetDisableWhenClean(Control ctl)
324 {
325 if (_sources.ContainsKey(ctl))
326 return _sources[ctl].DisableWhenClean;
327
328 return CslaActionExtenderProperties.DisableWhenCleanDefault;
329 }
330
336 [Category("Csla")]
337 [Description("If True, then the dirtiness of the underlying business object will cause this button to be enabled or disabled.")]
338 [Bindable(true)]
339 [DefaultValue(true)]
340 [Obsolete("Use instead DisableWhenUseless")]
341 [Browsable(false)]
342 public void SetDisableWhenClean(Control ctl, bool value)
343 {
344 if (_sources.ContainsKey(ctl))
345 _sources[ctl].DisableWhenClean = value;
346 else
347 {
348 CslaActionExtenderProperties props = new CslaActionExtenderProperties();
349 props.DisableWhenClean = value;
350 _sources.Add(ctl, props);
351 }
352 }
353
354 #endregion
355
356 #region DisableWhenUseless
357
362 [Category("Csla")]
363 [Description("If True, then the status of the underlying business object will cause this button to be enabled or disabled.")]
364 [Bindable(true)]
365 [DefaultValue(false)]
366 public bool GetDisableWhenUseless(Control ctl)
367 {
368 if (_sources.ContainsKey(ctl))
369 return _sources[ctl].DisableWhenUseless;
370
371 return CslaActionExtenderProperties.DisableWhenUselessDefault;
372 }
373
379 [Category("Csla")]
380 [Description("If True, then the status of the underlying business object will cause this button to be enabled or disabled.")]
381 [Bindable(true)]
382 [DefaultValue(true)]
383 public void SetDisableWhenUseless(Control ctl, bool value)
384 {
385 if (_sources.ContainsKey(ctl))
386 _sources[ctl].DisableWhenUseless = value;
387 else
388 {
389 CslaActionExtenderProperties props = new CslaActionExtenderProperties();
390 props.DisableWhenUseless = value;
391 _sources.Add(ctl, props);
392 }
393 }
394
395 #endregion
396
397 #region CommandName
398
403 [Category("Csla")]
404 [Description("Gets or sets the name of this command control for unique identification purposes.")]
405 [Bindable(true)]
406 [DefaultValue("")]
407 public string GetCommandName(Control ctl)
408 {
409 if (_sources.ContainsKey(ctl))
410 return _sources[ctl].CommandName;
411
412 return CslaActionExtenderProperties.CommandNameDefault;
413 }
414
420 [Category("Csla")]
421 [Description("Gets or sets the name of this command control for unique identification purposes.")]
422 [Bindable(true)]
423 [DefaultValue("")]
424 public void SetCommandName(Control ctl, string value)
425 {
426 if (_sources.ContainsKey(ctl))
427 _sources[ctl].CommandName = value;
428 else
429 {
430 CslaActionExtenderProperties props = new CslaActionExtenderProperties();
431 props.CommandName = value;
432 _sources.Add(ctl, props);
433 }
434 }
435
436 #endregion
437
438 #endregion
439
440 #region Event declarations
441
445 [Category("Csla")]
446 [Description("Event fires just before the attempted action.")]
447 public event EventHandler<CslaActionCancelEventArgs> Clicking;
448
452 [Category("Csla")]
453 [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.")]
454 public event EventHandler<CslaActionEventArgs> Clicked;
455
459 [Category("Csla")]
460 [Description("Event fires upon encountering any exception during an action.")]
461 public event EventHandler<ErrorEncounteredEventArgs> ErrorEncountered;
462
466 [Category("Csla")]
467 [Description("Event fires upon a successful save when the PostSaveAction property is set to AndNew.")]
468 public event EventHandler<CslaActionEventArgs> SetForNew;
469
473 [Category("Csla")]
474 [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.")]
475 public event EventHandler<CslaActionEventArgs> BusinessObjectInvalid;
476
480 [Category("Csla")]
481 [Description("Event fires if there are any broken rules at all, despite severity.")]
482 public event EventHandler<HasBrokenRulesEventArgs> HasBrokenRules;
483
487 [Category("Csla")]
488 [Description("Fires just before a save action is performed.")]
489 public event EventHandler<CslaActionCancelEventArgs> ObjectSaving;
490
494 [Category("Csla")]
495 [Description("Fires immediately after the underlying object successfully saves.")]
496 public event EventHandler<CslaActionEventArgs> ObjectSaved;
497
498 #endregion
499
500 #region OnEvent methods
501
506 protected virtual void OnClicking(CslaActionCancelEventArgs e)
507 {
508 if (Clicking != null)
509 Clicking(this, e);
510 }
511
516 protected virtual void OnClicked(CslaActionEventArgs e)
517 {
518 if (Clicked != null)
519 Clicked(this, e);
520 }
521
527 {
528 if (ErrorEncountered != null)
529 ErrorEncountered(this, e);
530 }
531
536 protected virtual void OnSetForNew(CslaActionEventArgs e)
537 {
538 if (SetForNew != null)
539 SetForNew(this, e);
540 }
541
547 {
548 if (BusinessObjectInvalid != null)
549 BusinessObjectInvalid(this, e);
550 }
551
557 {
558 if (HasBrokenRules != null)
559 HasBrokenRules(this, e);
560 }
561
567 {
568 if (ObjectSaving != null)
569 ObjectSaving(this, e);
570 }
571
576 protected virtual void OnObjectSaved(CslaActionEventArgs e)
577 {
578 if (ObjectSaved != null)
579 ObjectSaved(this, e);
580 }
581
582 #endregion
583
584 #region Public methods
585
590 public void ResetActionBehaviors(ISavable objectToBind)
591 {
592 InitializeControls(true);
593
594 BindingSource rootSource = _dataSource as BindingSource;
595
596 if (rootSource != null)
597 {
598 AddEventHooks(objectToBind);
599 }
600
601 _bindingSourceTree = BindingSourceHelper.InitializeBindingSourceTree(_container, rootSource);
602 _bindingSourceTree.Bind(objectToBind);
603 }
604
605 private void AddEventHooks(ISavable objectToBind)
606 {
607 // make sure to not attach many times
608 RemoveEventHooks(objectToBind);
609
610 INotifyPropertyChanged propChangedObjParent = objectToBind as INotifyPropertyChanged;
611 if (propChangedObjParent != null)
612 {
613 propChangedObjParent.PropertyChanged += propChangedObj_PropertyChanged;
614 }
615
616 INotifyChildChanged propChangedObjChild = objectToBind as INotifyChildChanged;
617 if (propChangedObjChild != null)
618 {
619 propChangedObjChild.ChildChanged += propChangedObj_ChildChanged;
620 }
621 }
622
623 private void RemoveEventHooks(ISavable objectToBind)
624 {
625 INotifyPropertyChanged propChangedObjParent = objectToBind as INotifyPropertyChanged;
626 if (propChangedObjParent != null)
627 {
628 propChangedObjParent.PropertyChanged -= propChangedObj_PropertyChanged;
629 }
630
631 INotifyChildChanged propChangedObjChild = objectToBind as INotifyChildChanged;
632 if (propChangedObjChild != null)
633 {
634 propChangedObjChild.ChildChanged -= propChangedObj_ChildChanged;
635 }
636 }
637
638 private void propChangedObj_ChildChanged(object sender, ChildChangedEventArgs e)
639 {
640 ResetControls();
641 }
642
643 private void propChangedObj_PropertyChanged(object sender, PropertyChangedEventArgs e)
644 {
645 ResetControls();
646 }
647
648 #endregion
649
650 #region Protected methods
651
657 protected void OnClick(object sender, EventArgs e)
658 {
659 Control ctl = (Control) sender;
660 CslaActionExtenderProperties props = _sources[ctl];
661 if (props.ActionType != CslaFormAction.None)
662 {
663 try
664 {
665 bool raiseClicked = true;
666 CslaActionCancelEventArgs args = new CslaActionCancelEventArgs(false, props.CommandName);
667 OnClicking(args);
668 if (!args.Cancel)
669 {
670 ISavable savableObject = null;
671 ITrackStatus trackableObject = null;
672 BindingSource source = null;
673
674 var sourceObjectError = false;
675 if (_dataSource != null)
676 {
677 source = _dataSource as BindingSource;
678
679 if (source != null)
680 {
681 savableObject = source.DataSource as ISavable;
682 trackableObject = source.DataSource as ITrackStatus;
683 }
684 else
685 {
686 OnErrorEncountered(new ErrorEncounteredEventArgs(props.CommandName, new InvalidCastException(Resources.ActionExtenderInvalidBindingSourceCast)));
687 sourceObjectError = true;
688 }
689
690 if (savableObject == null || trackableObject == null)
691 {
693 sourceObjectError = true;
694 }
695 }
696
697 if (!sourceObjectError)
698 {
699 DialogResult diagResult;
700
701 switch (props.ActionType)
702 {
703 case CslaFormAction.Save:
704 raiseClicked = ExecuteSaveAction(savableObject, trackableObject, props);
705 break;
706 // case CslaFormAction.Save
707
708 case CslaFormAction.Cancel:
709
710 diagResult = DialogResult.Yes;
711 if (_warnOnCancel && trackableObject.IsDirty)
712 diagResult = MessageBox.Show(
713 _warnOnCancelMessage, Resources.Warning,
714 MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
715
716 if (diagResult == DialogResult.Yes)
717 _bindingSourceTree.Cancel(savableObject);
718
719 break;
720 // case CslaFormAction.Cancel
721
722 case CslaFormAction.Close:
723
724 diagResult = DialogResult.Yes;
725 if (trackableObject.IsDirty || trackableObject.IsNew)
726 {
727 if (_warnIfCloseOnDirty)
728 diagResult = MessageBox.Show(
729 _dirtyWarningMessage + Environment.NewLine + Resources.ActionExtenderCloseConfirmation,
730 Resources.Warning, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
731 }
732
733 if (diagResult == DialogResult.Yes)
734 {
735 _bindingSourceTree.Close();
736 _closeForm = true;
737 }
738
739 break;
740 // case CslaFormAction.Close
741
742 case CslaFormAction.Validate:
743
744 if (savableObject is BusinessBase)
745 {
746 BusinessBase businessObject = savableObject as BusinessBase;
747 if (!businessObject.IsValid)
748 {
749 string brokenRules = string.Empty;
750 foreach (var brokenRule in businessObject.GetBrokenRules())
751 {
752 var lambdaBrokenRule = brokenRule;
753 var friendlyName =
754 PropertyInfoManager.GetRegisteredProperties(businessObject.GetType()).Find(
755 c => c.Name == lambdaBrokenRule.Property).FriendlyName;
756 brokenRules += string.Format("{0}: {1}{2}", friendlyName, brokenRule, Environment.NewLine);
757 }
758 MessageBox.Show(brokenRules, Resources.ActionExtenderErrorCaption,
759 MessageBoxButtons.OK, MessageBoxIcon.Error);
760 }
761 else
762 {
763 MessageBox.Show(_objectIsValidMessage, Resources.ActionExtenderInformationCaption,
764 MessageBoxButtons.OK, MessageBoxIcon.Information);
765 }
766 }
767
768 break;
769 //case CslaFormAction.Validate
770
771 } // switch (props.ActionType)
772
773 // raiseClicked is true if
774 // ActionType == CslaFormAction.Save and everything is ok
775 if (raiseClicked)
776 {
777 if (props.ActionType == CslaFormAction.Save && source != null)
778 {
779 if (props.RebindAfterSave)
780 {
781 // For some strange reason, this has to be done down here.
782 // Putting it in the Select Case AfterSave... does not work.
783 _bindingSourceTree.ResetBindings(false);
784 InitializeControls(true);
785 }
786 }
787 else
788 {
789 if (props.ActionType == CslaFormAction.Cancel)
790 InitializeControls(true);
791 }
792
793 OnClicked(new CslaActionEventArgs(props.CommandName));
794 }
795
796 } // if (!sourceObjectError)
797
798 } // if (!args.Cancel)
799
800 if (_closeForm)
801 CloseForm();
802 }
803 catch (Exception ex)
804 {
805 OnErrorEncountered(new ErrorEncounteredEventArgs(props.CommandName, ex));
806 }
807 } // if (props.ActionType != CslaFormAction.None)
808 }
809
810 #endregion
811
812 #region Private methods
813
814 private bool ExecuteSaveAction(ISavable savableObject, ITrackStatus trackableObject, CslaActionExtenderProperties props)
815 {
816 var result = true;
817 bool okToContinue = true;
818
819 BusinessBase businessObject = null;
820 bool savableObjectIsBusinessBase = savableObject is BusinessBase;
821 if (savableObjectIsBusinessBase)
822 businessObject = savableObject as BusinessBase;
823
824 if (savableObjectIsBusinessBase)
825 {
826 if (!businessObject.IsValid)
827 {
828 HasBrokenRulesEventArgs argsHasBrokenRules = new HasBrokenRulesEventArgs(
829 props.CommandName,
830 businessObject.GetBrokenRules().ErrorCount > 0,
831 businessObject.GetBrokenRules().WarningCount > 0,
832 businessObject.GetBrokenRules().InformationCount > 0,
833 _autoShowBrokenRules);
834
835 OnHasBrokenRules(argsHasBrokenRules);
836
837 okToContinue = !argsHasBrokenRules.Cancel;
838 //in case the client changed it
839 _autoShowBrokenRules = argsHasBrokenRules.AutoShowBrokenRules;
840 }
841 }
842
843 if (okToContinue)
844 {
845 if (savableObjectIsBusinessBase)
846 {
847 if (_autoShowBrokenRules && !businessObject.IsValid)
848 {
849 string brokenRules = string.Empty;
850 foreach (var brokenRule in businessObject.GetBrokenRules())
851 {
852 var lambdaBrokenRule = brokenRule;
853 var friendlyName =
854 PropertyInfoManager.GetRegisteredProperties(businessObject.GetType()).Find(
855 c => c.Name == lambdaBrokenRule.Property).FriendlyName;
856 brokenRules += string.Format("{0}: {1}{2}", friendlyName, brokenRule, Environment.NewLine);
857 }
858 MessageBox.Show(brokenRules, Resources.ActionExtenderErrorCaption,
859 MessageBoxButtons.OK, MessageBoxIcon.Error);
860 }
861 }
862
863 if (trackableObject.IsValid)
864 {
865 CslaActionCancelEventArgs savingArgs = new CslaActionCancelEventArgs(false, props.CommandName);
866 OnObjectSaving(savingArgs);
867
868 if (!savingArgs.Cancel)
869 {
870 _bindingSourceTree.Apply();
871 ISavable objectToSave;
872
873 if (Csla.ApplicationContext.AutoCloneOnUpdate == false)
874 objectToSave = ((ICloneable)savableObject).Clone() as ISavable;// if not AutoClone, clone manually
875 else
876 objectToSave = savableObject;
877
878 if (objectToSave != null)
879 {
880 try
881 {
882 RemoveEventHooks(savableObject);
883 savableObject = savableObject.Save() as ISavable;
884
885 OnObjectSaved(new CslaActionEventArgs(props.CommandName));
886
887 switch (props.PostSaveAction)
888 {
889 case PostSaveActionType.None:
890
891 if (props.RebindAfterSave)
892 {
893 _bindingSourceTree.Bind(savableObject);
894 AddEventHooks(savableObject);
895 }
896 break;
897
898 case PostSaveActionType.AndClose:
899
900 CloseForm();
901 break;
902
903 case PostSaveActionType.AndNew:
904
905 OnSetForNew(new CslaActionEventArgs(props.CommandName));
906 AddEventHooks(savableObject);
907 break;
908 }
909 }
910 catch (Exception ex)
911 {
912 _bindingSourceTree.Bind(objectToSave);
913 AddEventHooks(objectToSave);
914 OnErrorEncountered(new ErrorEncounteredEventArgs(props.CommandName, new ObjectSaveException(ex)));
915 // there was some problem
916 result = false;
917 }
918 }
919 else
920 {
921 // did not find bound object so don't bother raising the Clicked event
922 result = false;
923 }
924
925 _bindingSourceTree.SetEvents(true);
926 }
927 }
928 else
929 {
930 OnBusinessObjectInvalid(new CslaActionEventArgs(props.CommandName));
931 // object not valid or has broken rules set to invalidate it due to this control's properties
932 result = false;
933 }
934 }
935 else
936 {
937 // process was canceled from the HasBrokenRules event (okToContinue = false)
938 result = false;
939 }
940
941 return result;
942 }
943
944 private void ResetControls()
945 {
946 InitializeControls(false);
947 }
948
949 private void InitializeControls(bool initialEnabling)
950 {
951 // controls will not be enabled until the BusinessObjectPropertyChanged event fires or if it's in an appropriate state now
952 List<Control> extendedControls = new List<Control>();
953 foreach (KeyValuePair<Control, CslaActionExtenderProperties> pair in _sources)
954 {
955 if (pair.Value.ActionType != CslaFormAction.None)
956 {
957 Control ctl = pair.Key;
958 if (initialEnabling)
959 {
960 if (pair.Value.DisableWhenUseless || pair.Value.DisableWhenClean)
961 ChangeEnabled(ctl, !(pair.Value.DisableWhenUseless || pair.Value.DisableWhenClean));
962 pair.Key.Click -= OnClick;
963 pair.Key.Click += OnClick;
964 }
965 InitializeControl(ctl, pair);
966 extendedControls.Add(ctl);
967 }
968 }
969 }
970
971 private void InitializeControl(Control ctl, KeyValuePair<Control, CslaActionExtenderProperties> pair)
972 {
973 if (pair.Value.DisableWhenUseless || (pair.Value.DisableWhenClean && !ctl.Enabled))
974 {
975 ISavable businessObject = GetBusinessObject();
976 if (businessObject != null)
977 {
978 ITrackStatus trackableObject = businessObject as ITrackStatus;
979 if (trackableObject != null)
980 {
981 if (pair.Value.ActionType == CslaFormAction.Cancel || pair.Value.DisableWhenClean)
982 ChangeEnabled(ctl, trackableObject.IsNew || trackableObject.IsDirty || trackableObject.IsDeleted);
983 if (pair.Value.ActionType == CslaFormAction.Save)
984 ChangeEnabled(ctl, (trackableObject.IsNew || trackableObject.IsDirty || trackableObject.IsDeleted)
985 && trackableObject.IsValid);
986 }
987 }
988 }
989 }
990
991 private void ChangeEnabled(Control ctl, bool newEnabled)
992 {
993 // only do this if it's changed to avoid flicker
994 if (ctl.Enabled != newEnabled)
995 ctl.Enabled = newEnabled;
996 }
997
998 private void CloseForm()
999 {
1000 if (_sources.Count > 0)
1001 {
1002 Dictionary<Control, CslaActionExtenderProperties>.Enumerator enumerator = _sources.GetEnumerator();
1003 if (enumerator.MoveNext())
1004 {
1005 Control ctl = enumerator.Current.Key;
1006 Form frm = GetParentForm(ctl);
1007 if (frm != null)
1008 frm.Close();
1009 }
1010 }
1011 }
1012
1013 private Form GetParentForm(Control thisControl)
1014 {
1015 Form frm;
1016
1017 if (thisControl.Parent is Form)
1018 frm = (Form) thisControl.Parent;
1019 else
1020 frm = GetParentForm(thisControl.Parent);
1021
1022 return frm;
1023 }
1024
1025 private ISavable GetBusinessObject()
1026 {
1027 ISavable businessObject = null;
1028 BindingSource source = _dataSource as BindingSource;
1029 if (source != null)
1030 businessObject = source.DataSource as ISavable;
1031
1032 return businessObject;
1033 }
1034
1035 #endregion
1036 }
1037}
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.
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 SetDisableWhenClean(Control ctl, bool value)
Sets the disable when clean value.
void SetRebindAfterSave(Control ctl, bool value)
Sets the rebind after save value.
EventHandler< ErrorEncounteredEventArgs > ErrorEncountered
Event indicating an error was encountered.
bool GetDisableWhenClean(Control ctl)
Gets the disable when clean value.
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 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.
Definition: ISavableT.cs:19
object Save()
Saves the object to the database.
Defines the common properties required objects that track their own status.
Definition: ITrackStatus.cs:17
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...
Definition: ITrackStatus.cs:37
bool IsDirty
Returns true if this object's data, or any of its fields or child objects data, has been changed.
Definition: ITrackStatus.cs:73
CslaFormAction
The possible form actions.
Definition: Enums.cs:14
PostSaveActionType
The possible actions for post save.
Definition: Enums.cs:41