The PDFx is a lightweight open source .NET library that allows developers to describe dependencies between Properties in declarative C# code. Once relationships are registered, the framework monitors property changes and ensures that the INotifyPropertyChanged.PropertyChanged event is fired for all directly and indirectly dependent properties in a very efficient way. The library is available for WPF, Silverlight, WinRT (Windows Store) and Windows Phone.
I’ve developed the PDFx as an InterKnowlogy RECESS project and published the source code and examples on codeplex.
In a series of blog posts I am going to cover the library’s most important features:
- Part I: Introduction
- Part II: Library Versions
- Part III: Getting Started
- Part IV: Using PDFx with an existing 3rd party framework
- Part V: Simple Property Dependencies
- Part VI: External Property Dependencies
- Part VII: Dynamic External Property Dependencies
- Part VIII: Collection Dependencies
- Part IX: Dynamic Collection Dependencies
- Part X: Caching
- Part XI: Smart Property Changed Notification
- Part XII: Callbacks
- Part XIII: Sanity Checks
- Part XIV: Data Delegation
- Part XV: Two Way Converters
- Part XVI: One Way Converters
Dynamic External Property Dependencies
Declarative Usage
As shown in External Property Dependencies, the declarative PDFx API allows you to register a dependency on a property that resides in any INotifyPropertyChanged-instance different from the owner of the dependent Property.
If the owner of the source property can be swapped out at runtime (or start off as null), you can instruct PDFx to listen for changes of the owner object:
class SourceClass : INotifyPropertyChanged { private AnyType _sourceProperty; public AnyType SourceProperty { get { return _sourceProperty; } set { _sourceProperty = value; OnPropertyChanged("SourceProperty"); } } } class DestinationClass : BindableExt { private SourceClass _dynamicSource; private SourceClass DynSource { get { return _dynamicSource; } set { _dynamicSource = value; NotifyPropertyChanged(() => DynSource); } } public AnyOtherType TargetProperty { get { Property(() => TargetProperty) .Depends(p => p.On(() => DynSource, k => k.SourceProperty)); //Note that the first parameter of the On method is a delegate //SourceProperty has changed. Do Something with it and return. } } public void ChangeSource() { DynSource = new SourceClass(); } }
Overloads of the methods On and AndOn both allow you to pass in an INotifyPropertyChanged instance as the first parameter and point to any property of that instance in the Lambda Expression you pass in as the second parameter.
To support hot swapping of the INotifyPropertyChanged instance, you pass in a delegate to the On and AndOn overloads, which points to the Property that contains the Source Property owner.
Example
The source code of this example can be found in ViewModel DynamicExternalDependencyVM which is part of the WPFSample’s source code.
Let’s assume we are required to implement the following graph:
By clicking the “Use External Source”-buttons, the user can change the source “External Source” that ultimately feeds into the Destination object:
Green circles stand for Input Properties while purple circles indicate calculated properties. The arrows show the underlying math operations as well as the property dependencies.
Using the PDFx, we can easily represent the depicted graph in C#:
public class DynamicExternalDependencyVM : BindableExt { public DynamicExternalDependencyVM() { ExternalSource1 = new ExternalSource(); ExternalSource2 = new ExternalSource(); Destination = new DestinationVM() { ExternalSource = ExternalSource1 }; } public DestinationVM Destination { get; set; } public ExternalSource ExternalSource1 { get; set; } public ExternalSource ExternalSource2 { get; set; } private DelegateCommand _useExternalSource1Command; public DelegateCommand UseExternalSource1Command { get { return _useExternalSource1Command = _useExternalSource1Command ?? new DelegateCommand(() => Destination.ExternalSource = ExternalSource1); //Hotswap ExternalSource } } private DelegateCommand _useExternalSource2Command; public DelegateCommand UseExternalSource2Command { get { return _useExternalSource2Command = _useExternalSource2Command ?? new DelegateCommand(() => Destination.ExternalSource = ExternalSource2); //Hotswap ExternalSource } } public class DestinationVM : BindableExt { public int A1 { get { Property(() => A1) .Depends(p => p.On(() => B1) .AndOn(() => ExternalSource, k => k.A1)); //Tell the PDFx that ExternalSource might get hotswapped return B1 + ExternalSource.A1; } } private ExternalSource _externalSource; public ExternalSource ExternalSource { get { return _externalSource; } set { _externalSource = value; NotifyPropertyChanged(() => ExternalSource); } } private int _b1; public int B1 { get { return _b1; } set { _b1 = value; NotifyPropertyChanged(() => B1); } } } public class ExternalSource : BindableExt { public int A1 { get { Property(() => A1) .Depends(p => p.On(() => B1)); return 3 * B1; } } private int _b1; public int B1 { get { return _b1; } set { _b1 = value; NotifyPropertyChanged(() => B1); } } } }
Pingback: PDFx – Property Dependency Framework – Part I, Introduction | //InterKnowlogy/ Blogs
Pingback: PDFx – Property Dependency Framework – Part II, Library Versions | //InterKnowlogy/ Blogs
Pingback: PDFx – Property Dependency Framework – Part III, Getting started | //InterKnowlogy/ Blogs
Pingback: PDFx – Property Dependency Framework – Part VIII, Collection Dependencies | //InterKnowlogy/ Blogs