10using System.ComponentModel;
14using System.Reflection;
15using System.Collections.ObjectModel;
18using Windows.UI.Xaml.Data;
21using System.Collections.Generic;
23using System.Windows.Controls;
25using System.Windows.Data;
34 public class PropertyInfo : View, INotifyPropertyChanged
38 public class PropertyInfo : FrameworkElement, INotifyPropertyChanged
40 private const string _dependencyPropertySuffix =
"Property";
42 private bool _loading =
true;
49 BrokenRules =
new ObservableCollection<BrokenRule>();
52 BindingContextChanged += (o, e) =>
SetSource();
55 Visibility = Visibility.Collapsed;
77 #region BrokenRules property
85 BindableProperty.Create(
"BrokenRules", typeof(ObservableCollection<BrokenRule>), typeof(
PropertyInfo),
new ObservableCollection<BrokenRule>());
102 typeof(ObservableCollection<BrokenRule>),
110 [Category(
"Property Status")]
120 #region MyDataContext Property
128 DependencyProperty.Register(
"MyDataContext",
132 new PropertyMetadata(
null, MyDataContextPropertyChanged));
134 new PropertyMetadata(MyDataContextPropertyChanged));
137 private static void MyDataContextPropertyChanged(
object sender, DependencyPropertyChangedEventArgs e)
145 #region RelativeBinding Property
154 DependencyProperty.Register(
"RelativeBinding",
158 new PropertyMetadata(
null, RelativeBindingPropertyChanged));
160 new PropertyMetadata(RelativeBindingPropertyChanged));
163 private static void RelativeBindingPropertyChanged(
object sender, DependencyPropertyChangedEventArgs e)
171 #region Source property
186 private string _bindingPath;
194 get {
return _bindingPath; }
197 if (_bindingPath != value)
199 _bindingPath = value;
206 private class SourceReference
208 public SourceReference(
PropertyInfo parent,
object source,
string propertyName)
212 PropertyName = propertyName;
213 var p =
Source as INotifyPropertyChanged;
215 p.PropertyChanged += P_PropertyChanged;
218 private void P_PropertyChanged(
object sender, PropertyChangedEventArgs e)
220 if (e.PropertyName == PropertyName)
224 public void DetachHandlers()
226 var p =
Source as INotifyPropertyChanged;
228 p.PropertyChanged -= P_PropertyChanged;
232 public object Source {
get;
private set; }
233 public string PropertyName {
get;
private set; }
236 private List<SourceReference> _sources =
new List<SourceReference>();
240 foreach (var item
in _sources)
241 item.DetachHandlers();
253 _sources.Add(
new SourceReference(
this,
Source, refName));
255 Source = MethodCaller.CallPropertyGetter(
Source, refName);
260 throw new InvalidOperationException(
261 string.Format(
"SetSource: BindingContext:{0}, Path={1}",
BindingPath.GetType().Name, Path), ex);
264 HandleSourceEvents(oldSource,
Source);
277 new PropertyMetadata(
new object(), (o, e) =>
280 if (e.NewValue ==
null)
282 if (e.OldValue == null)
285 else if (e.NewValue.Equals(e.OldValue))
319 if (sourceBinding !=
null
320 && sourceBinding.ParentBinding.RelativeSource !=
null
321 && sourceBinding.ParentBinding.RelativeSource.Mode == RelativeSourceMode.TemplatedParent
322 && sourceBinding.DataItem is FrameworkElement)
324 var control = (FrameworkElement)sourceBinding.DataItem;
325 var path = sourceBinding.ParentBinding.Path.Path;
327 var type = control.GetType();
332 fi = type.GetField(
string.Format(
"{0}{1}", path, _dependencyPropertySuffix), BindingFlags.Instance | BindingFlags.Public);
334 fi = type.GetField(
string.Format(
"{0}{1}", path, _dependencyPropertySuffix));
339 DependencyProperty mappedDP = (DependencyProperty)fi.GetValue(control.GetType());
340 return control.GetBindingExpression(mappedDP);
345 type = type.GetTypeInfo().BaseType;
347 type = type.BaseType;
355 return sourceBinding;
361 protected virtual void SetSource(
bool propertyValueChanged)
375 bool isDataLoaded =
true;
382 if (newSource !=
null && newSource is FrameworkElement)
384 var data = ((FrameworkElement)newSource).DataContext;
390 if (relativeBinding !=
null)
396 if (newSource !=
null)
398 Binding b =
new Binding();
399 b.Source = newSource;
407 && !
string.IsNullOrEmpty(b.Path.Path)
411 isDataLoaded =
false;
421 if (!ReferenceEquals(
Source, newSource))
426 HandleSourceEvents(old,
Source);
436 private void SetBindingValues(BindingExpression binding)
438 var bindingPath =
string.Empty;
442 if (binding.ParentBinding !=
null && binding.ParentBinding.Path !=
null)
443 bindingPath = binding.ParentBinding.Path.Path;
445 bindingPath =
string.Empty;
459 var icv = source as ICollectionView;
461 source = icv.CurrentItem;
462 if (source !=
null && bindingPath.IndexOf(
'.') > 0)
464 var firstProperty = bindingPath.Substring(0, bindingPath.IndexOf(
'.'));
465 var p = MethodCaller.GetProperty(source.GetType(), firstProperty);
469 MethodCaller.GetPropertyValue(source, p),
470 bindingPath.Substring(bindingPath.IndexOf(
'.') + 1));
487 if (bindingPath.IndexOf(
'.') > 0)
489 var firstProperty = bindingPath.Substring(0, bindingPath.IndexOf(
'.'));
490 var p = MethodCaller.GetProperty(source.GetType(), firstProperty);
493 return new PropertyPath(firstProperty);
495 return GetRelativePath(source, bindingPath.Substring(bindingPath.IndexOf(
'.') + 1));
498 return new PropertyPath(bindingPath);
505 private void HandleSourceEvents(
object old,
object source)
507 if (!ReferenceEquals(old, source))
510 AttachSource(source);
512 if (bb !=
null && !
string.IsNullOrWhiteSpace(
BindingPath))
519 private void DetachSource(
object source)
521 var p = source as INotifyPropertyChanged;
523 p.PropertyChanged -= source_PropertyChanged;
529 private void AttachSource(
object source)
531 var p = source as INotifyPropertyChanged;
533 p.PropertyChanged += source_PropertyChanged;
539 void source_PropertyChanged(
object sender, PropertyChangedEventArgs e)
541 if (e.PropertyName ==
BindingPath ||
string.IsNullOrEmpty(e.PropertyName))
567 #region Error/Warn/Info Text
578 var result =
string.Empty;
594 var result =
string.Empty;
610 var result =
string.Empty;
619 #region State properties
625 [Category(
"Property Status")]
630 object result =
null;
643 private bool _canRead =
true;
648 [Category(
"Property Status")]
651 get {
return _canRead; }
654 if (value != _canRead)
662 private bool _canWrite =
true;
667 [Category(
"Property Status")]
670 get {
return _canWrite; }
673 if (value != _canWrite)
681 private bool _isBusy =
false;
686 [Category(
"Property Status")]
689 get {
return _isBusy; }
692 if (value != _isBusy)
700 private bool _isValid =
true;
705 [Category(
"Property Status")]
708 get {
return _isValid; }
711 if (value != _isValid)
726 [Category(
"Property Status")]
729 get {
return _worst; }
740 private string _ruleDescription =
string.Empty;
745 [Category(
"Property Status")]
748 get {
return _ruleDescription; }
751 if (value != _ruleDescription)
753 _ruleDescription = value;
759 private object _customTag;
764 [Category(
"Property Status")]
773 if (!ReferenceEquals(_customTag, value))
783 #region State management
792 if (_loading)
return;
813 var allRules = (from r in businessObject.BrokenRulesCollection
818 where !allRules.Contains(r)
821 var addRules = (from r in allRules
825 foreach (var rule
in removeRules)
827 foreach (var rule
in addRules)
836 select r).FirstOrDefault();
866 #region INotifyPropertyChanged Members
This is the base class from which most business objects will be derived.
This is the non-generic base class from which most business objects will be derived.
virtual bool IsPropertyBusy(Csla.Core.IPropertyInfo property)
Gets a value indicating whether a specific property is busy (has a currently executing async rule).
Event arguments for the BusyChanged event.
string PropertyName
Property for which the Busy value has changed.
Stores details about a specific broken business rule.
string Description
Provides access to the description of the broken rule.
RuleSeverity Severity
Gets the severity of the broken rule.
Expose metastate information about a property.
object Value
Gets and sets the value of the property on the business object.
string WarningText
Gets the validation warning messages for a property on the Model
string ErrorText
Gets the validation error messages for a property on the Model
bool CanRead
Gets a value indicating whether the user is authorized to read the property.
string InformationText
Gets the validation information messages for a property on the Model
string RuleDescription
Gets the description of the most severe broken rule for this property.
virtual void UpdateState()
Updates the metastate values on control based on the current state of the business object and propert...
string BindingPath
Gets or sets the binding path.
PropertyInfo(bool testing)
Creates an instance of the object for testing.
object Source
Gets or sets the Source.
bool IsBusy
Gets a value indicating whether the property is busy with an asynchronous operation.
bool CanWrite
Gets a value indicating whether the user is authorized to write the property.
virtual void SetSource(bool propertyValueChanged)
Sets the source binding and updates status.
static readonly DependencyProperty RelativeBindingProperty
Used to monitor for changes in the binding path.
PropertyInfo()
Creates an instance of the object.
static readonly DependencyProperty MyDataContextProperty
Used to monitor for changes in the binding path.
PropertyChangedEventHandler PropertyChanged
Event raised when a property has changed.
virtual void OnPropertyChanged(string propertyName)
Raises the PropertyChanged event.
static readonly DependencyProperty PropertyProperty
Gets or sets the source business property to which this control is bound.
static readonly DependencyProperty BrokenRulesProperty
Gets the broken rules collection from the business object.
bool IsValid
Gets a value indicating whether the property is valid.
virtual BindingExpression ParseRelativeBinding(BindingExpression sourceBinding)
Checks a binding expression to see if it is a relative source binding used in a control template.
ObservableCollection< BrokenRule > BrokenRules
Gets the broken rules collection from the business object.
object CustomTag
Gets or sets an arbitrary value associated with this PropertyInfo instance.
object Property
Gets or sets the source business property to which this control is bound.
virtual void SetSource(object dataItem)
Sets the source binding and updates status.
PropertyPath GetRelativePath(object source, string bindingPath)
Gets the part of the binding path relevant to the given source.
object GetRealSource(object source, string bindingPath)
Gets the real source helper method.
Interface defining an object that notifies when it is busy executing an asynchronous operation.
BusyChangedEventHandler BusyChanged
Event raised when the object's busy status changes.
Defines the authorization interface through which an object can indicate which properties the current...
RuleSeverity
Values for validation rule severities.