Xaml design time data: Radical.Design dynamic reactions
Where we are:
- We have introduced the design time data concepts;
- We have understood how to setup a design time experience using Radical;
- We have discovered how to let the designers lively change values at design time;
We want more!
Start changing the view model we are designing adding a couple of properties:
class PersonViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged = ( s, e ) => { }; private void OnPropertyChanged( string propertyName ) { var h = this.PropertyChanged; h( this, new PropertyChangedEventArgs( propertyName ) ); } String _firstName; public String FirstName { get { return _firstName; } set { _firstName = value; this.OnPropertyChanged( "FirstName" ); } } String _lastName; public String LastName { get { return _lastName; } set { _lastName = value; this.OnPropertyChanged( "LastName" ); } } DateTime _bornDate; public DateTime BornDate { get { return _bornDate; } set { _bornDate = value; this.OnPropertyChanged( "BornDate" ); this.OnPropertyChanged( "Age" ); } } public Int32 Age { //stupid and wrong but it's a sample :-) get { return DateTime.Now.Year - this.BornDate.Year; } } }
We want to reflect that behavior in our design time view model, let’s start exposing a live property for the BornDate property:
public DesignTimePersonViewModel() { this.Expose( vm => vm.FirstName ) .WithLiveValue( () => this.DesignTime_FirstName ); this.Expose( vm => vm.LastName ) .WithLiveValue( () => this.DesignTime_LastName ); this.Expose( vm => vm.BornDate ) .WithLiveValue( () => this.DesignTime_BornDate ); } public DateTime DesignTime_BornDate { get { return this.GetPropertyValue( () => this.DesignTime_BornDate ); } set { this.SetPropertyValue( () => this.DesignTime_BornDate, value ); } }
Now we now, as we have seen last time, that we can edit the BornDate property directly in the designer, but what about the Age property? it is a runtime evaluated property.
Enter design time evaluated properties, aka dynamic properties:
public DesignTimePersonViewModel() { this.GetPropertyMetadata( () => this.DesignTime_BornDate ) .AddCascadeChangeNotifications( "Age" ); this.Expose( vm => vm.FirstName ) .WithLiveValue( () => this.DesignTime_FirstName ); this.Expose( vm => vm.LastName ) .WithLiveValue( () => this.DesignTime_LastName ); this.Expose( vm => vm.BornDate ) .WithLiveValue( () => this.DesignTime_BornDate ); this.Expose( vm => vm.Age ) .AsReadOnly() .WithDynamicValue( ci => ( int )( ( DateTime.Now - this.DesignTime_BornDate ).TotalDays / 365 ) ); }
We are doing some important things:
- we are telling to the infrastructure that whenever the DesignTime_BornDate property changes we want a changed event even for the Age property, I’m thinking about a better API to express this;
- We are building a dynamic value based property where the value is a Func<CultureInfo, TValue> that is invoked by the infrastructure to read the property value;
- Least but not last we are telling to the designer that the exposed Age property is a read-only property as in the original ViewModel;
And obviously the designer behaves as expected, immediately reflecting our inputs:
And the generated xaml code is exactly what we expect.
In the next episode of this series we’ll dive into a much more complex ViewModel scenario.
Stay tuned!
.m