Introduction
Common static class defines the
Attached Properties that, in conjunction with
Entity Controls, simplifies building UI code of business applications.
Let's see what these properties are and why they are useful.
TypeContext attached property
As you already know,
DataContext property is a property of type object defined in the FrameworkElement class. It's meant to be used for
data binding scenarios and is the default Binding Source.
Unfortunately, the
actual type of the value inside DataContext is not known until runtime, when a value is inserted, neither the full
property path is known that goes from the original entity (root) to it. Having this information available will make setting-up our
Entity Controls much easier.
Common.TypeContext attached property, in conjunction with Common.Route, adds these contexts to your controls for you. There are two types of TypeContext:
public class TypeContext
{
public Type Type {...}
}
public class TypeSubContext : TypeContext
{
public TypeContext Parent {...}
public PropertyInfo PropertyInfo {...}
}
- TypeContext: The root of your context, the original IdentifiableEntity Type. Usually defined explicitly.
- TypeSubContext: Defines accessing a property over another TypeContext. The Type is then the PropertyType of this property. It's ment to be created by Common.Route property.
The following example defines the interface for ProjectDN deffined
here:
<UserControl x:Class="Bugs.Windows.Controls.Project"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:Signum.Windows;assembly=Signum.Windows"
xmlns:d="clr-namespace:Bugs.Entities;assembly=Bugs.Entities"
m:Common.TypeContect="d:ProjectDN"
MinWidth="300">
<StackPanel>
<m:ValueLine m:Common.Route="Name"/>
<m:ValueLine m:Common.Route="IsInternal" LabelText="Is Internal"/>
</StackPanel>
</UserControl>
Let's see how this Route mechanism works.
Route attached property
Route attached property tries to simplify common DataBindig when building the controls for your custom entities. It does many things when set:
- Update TypeContext conveniently.
- Set Type property when applied over any Entity Control (ValueLine, EntityLine, EntityCombo, EntityList or FileLine) sets the corresponding Type property.
- Create the Binding arranging all the binding options correctly (Mode, NotifyOnValidationError, ValidatesOnExceptions...) using the corresponding Binding target property.
- Find Implementation when applied over any control inheriting EntityBase (EntityLine/Combo/List) setting the current types in the ImplementedBy attribute on the server Schema and setting the Implementations property.
- Update LabelText with the last part of the Route value, if not set explicitly.
So writing something like this.
<StackPanel m:Common.TypeContext="d:MyEntityDN">
<m:EntityLine m:Common.Route="MyProperty"/>
</StackPanel>
Gets expanded to this pseudo-XAML:
<StackPanel m:Common.TypeContext="d:MyEntityDN">
<m:EntityLine
m:Common.Route="MyProperty"
m:Common.TypeContext="TypeSubContext MyProperty"
EntityType="MyPropertyType"
Entity="{Binding MyProperty, NotifyOnValidationError=true, ValidatesOnExceptions=true, ValidatesOnDataErrors=true}"
Implementations="Server.FindImplementations(MyEntityDN, MyProperty)"
LabelText="MyProperty"/>
</StackPanel>
As you see, the Common.TypeContext/Common.Route infrastructure is a huge time-saver. Let's see what properties are set when Common.Route is applied over Entity Controls.
| Control | Type property | Binding target property | Implementations property |
|---|
| ValueLine | ValueType | Value | |
| EntityLine | EntityType | Entity | Implementations |
| EntityList | EntitiesType and EntityType | Entities | Implementations |
| EntityCombo | EntityType | Entity | Implementations |
| FileLine | EntityType | Entity | |
| any other control | | DataContext | |
So you can use the same way of using
m.Common.Route for binding almost any control to your entity
Finally, the expressions you could write using in Common.Route are based in
Binging.Path expressions:
- Single Property:
m.Common.Route="propertyName" - Multiple Property:
m.Common.Route="propertyName.propertyName2" The '.' operator is able to concatenate in sub-properties of a property. - Source Transversal:
m.Common.Route="collection/propertyNameX" The '/' gets into the current element of a collection.
There's no support for specifying ownerType in this synthax because the type is 'statically' known using TypeContext. We haven't added [index] support yet.
IsReadOnly attached property
This attached property is inherited by all the sub tree, changing the behaviour of any
Entity Control, disabling anything that can actually modify the entity. (Remove, Search and Create buttons, disable ComboBox, etc...)
You can see more information of when each button is displayed in
Entity Controls.
IsLabelVisible attached property
Many EntityControls (ValueLine, EntityLine, FileLine and EntityCombo) have a label on the left side of it. This label is visible by default and simplifies layout for the very common scenario of label-control pairs. (you can write the whole pair in one line)
You can turn off the visibility of these labels just by doing
m:Common.IsLabelVisible="false".
This property is Inherited so it affects the whole sub-tree.
LabelWidth attached property
This property lets you control the width available for these labels on the right side.
This property is Inherited so it affects the whole sub-tree.
CurrentWindow attached property
Some
EntityControls need to know the current window (i.e. Creating). Usually they find out the current window by themselves but in complex DataTemplate you will have to tell them explicitly.
This property is Inherited so it affects the whole sub-tree.
Utility Methods
Commons static class also offers some useful methods:
public static Window FindCurrentWindow(this FrameworkElement fe);
public static bool NotSet(this DependencyObject depObj, DependencyProperty prop);
public static IEnumerable<DependencyObject> Parents(this DependencyObject child);
public static Visibility ToVisibility(this bool val);
public static bool FromVisibility(this Visibility val);
public static DependencyObject FindChildrenBreadthFirst(DependencyObject parent, Predicate<DependencyObject> predicate)