Signum Framework Logo
"Open framework that encourages convention over configuration, using C# code,
not XML files, to model at the right level of abstraction and achieve deadlines.
...but also has a full Linq provider, and syncs the schema for you!"
Login
RSS

Search

»



Main
Index
Map
Videos
Download
Source code
Tutorials
Forum
FAQ



Image



PoweredBy

Introduction

Navigation static class provides an aseptic and centralized way of moving from one Window to the next one without actually knowing the Window class that is going to be open. This way of changing how an entity has to be shown is easier.

Navigator provides three main methods:

  • View: Takes an entity and opens it with the right Windows and Control to see it.
  • Admin: Administrates all the entities of a given type using the right control for the detail of the selected entity.
  • Find: Opens a Search Window for the given queryName.

These three methods have overloads taking ViewOptions/AdminOptions/FindOptions respectively to customize the navigation.

In order to use any Navigator functionality first you have to set it up.

Setup Navigator

Navigator also is the holder of NavigationManager, that contains three dictionaries allowing us to set-up in a central point the configuration for each entity type.

Dictionary<Type, EntitySettings> Settings;
Dictionary<object, ViewSettings> ViewSettings;
Dictionary<string, TypeDN> ServerTypes; 

EntitySettings

EntitySetting class defines the basic behaviour that should be expected from an entity inside Signum.Windows. By filling up these settings we save time and errors setting up Entity Control's properties (Create, View, Find...).

EntitySettings are defined like this:

   public class EntitySettings
   {
       public Func<Control> View;
       public Func<Window> ViewWindow;
       public Func<bool, bool> IsCreable = admin => true; //is Admin
       public Func<bool, bool> IsReadOnly;
       public Func<bool, bool> IsViewable;
       public Action<ICollectionView> CollectionViewOperations; 
       public DataTemplate DataTemplate;
       public Func<ImageSource> Icon;
       
       public EntitySettings(bool isSimpleType)
       {
            if (isSimpleType)
            {
                IsReadOnly = admin => !admin;
                IsCreable = admin => admin;
                IsViewable = admin => admin;
                CollectionViewOperations = cv => cv.SortDescriptions.Add(new SortDescription("Id", ListSortDirection.Ascending));
            }
            else
            {
                IsReadOnly = admin => false;
                IsCreable = admin => true;
                IsViewable = admin => true;
            }
        }
    }

As you see, most of the fields are delegates instead. Lambda syntax is so terse that it adds almost no overhead over writing the constant itself, and this way you are free to vary the value at runtime.

  • View: Lambda to generate the Control that will be used to display the entity in a NormalWindow or a AdminWindow.
  • ViewWindows: Lambda to generate the Windows when viewing, in case NormalWindows don't fit your needs.
  • IsCreable: Lambda to know if the entity should be creable by the user, the parameter is true when you are in a admin scenario (Admin window or SearchWindow for the main entity of the row).
  • IsReadOnly: Lambda to know it the entity should be seen as ReadOnly, the parameter is true on admin scenarios.
  • IsViewable: Lambda to know if the View buttons have to be shown, true on SearchWindow.
  • CollectionViewOperations: Actions over the ICollectionView that have to be done by EntityList (sorting, grouping).
  • DataTemplate: DataTemplate that will be used by every EntityControls.
  • Icon: Lambda to get the Icon that will be used when Viewing.

EntityType constructor allows you to define the most important fields (apart from View) using just one bool value, isSimpleType. Simple Types usually are maintained from admin pages, there are few instances and are shorted by Id. Common entities, on the other side, are editable and maintained from any window.

QuerySetting

QuerySetting allows us to customize some basic options of SearchWindow.

    public class QuerySetting
    {
        public string Title;
        
        public QuerySetting()
        {
        }
    }

Currently, the only thing you can customize is the Title of the search window. Usually, however, you keep it null and a fall-back function is used:

"Finder of "  + (queryName is Type) ? Navigator.TypeName(((Type)queryName)) :  //Uses Name from TypeDN table, or Description attribute, or the PascalToSpaced ToString
                (queryName is Enum) ? EnumExtensions.NiceToString(queryName) :  //Uses Description attribute, or PascalToSpaced ToString
                queryName.ToString();

ServerTypes

When an Entity has to be shown on the user interface Reflector.FriendlyName is used by default.

This optional dictionary can be filled with the TypeDN entities on server to override this behaviour.

i.e When showing CustomerDN, show 'Client' instead of 'Customer'.

Really, TypeDN also uses FriendlyName by default to fill Name property, but it can change as time goes (it's data).

Example

Here you have an example of setting-up Navigation for the entities defined here

Navigator.NavigationManager = new NavigationManager
{
    Settings = new Dictionary<Type, EntitySettings>()
    {
        {typeof(BugDN), new EntitySettings(false){ View = ()=> new Bug()} },
        {typeof(ProjectDN), new EntitySettings(true){ View = ()=> new Project()} },
        {typeof(DeveloperDN), new EntitySettings(true){ View = ()=> new Developer()} },
        {typeof(CustomerDN), new EntitySettings(true){ View = ()=> new Customer()} },
    },
    QuerySetting = ((IQueryServer)Server.ServerProxy).GetQueryNames().ToDictionary(a => a, a => new QuerySetting(a)),
    ServerTypes = Server.RetrieveAll<TypeDN>().ToDictionary(a=>a.ClassName)
};

View

View command allow us to open windows (usually a NormalWindow) to view/edit an entity.

There are two overloads for Navigator's View method, the first one:

//General overload
public static object View(ViewOptions viewOptions, object entity)

Takes ViewOptions class as a parameter. This contains many properties to change View command behaviour:

public class ViewOptions : MarkupExtension
{
    public ViewButtons Buttons {...}
    public bool Clone {...}
    public bool Modal {...}
    public bool Admin {...}
    public TypeContext TypeContext {...}
    ...
}

public enum ViewButtons { OkCancel, //Usually for modal modifications of sub-entities OkCancelSaving, //Exceptional. Ok with save behaviour, i.e. Notes SaveClose, //Usually for non-modal root entity modifications (i.e. from SearchWindow) }

  • Buttons: Defines what buttons should be shown in the button of the NormalWindow. The default value is OkCancel.
  • Clone: Clones the original entity so the changes can be undone. The default value is true when Buttons == OkCancel
  • Modal: The default value is true when Buttons == ViewButtons.OkCancelSaving || Buttons == ViewButtons.OkCancel
  • Admin: Affects IsReadOnly of the whole NormalWindow when EntitySetting's IsReadonly lambda depends on admin parameter.
  • TypeContext: When navigating to an EmbeddedEntity that contains ImplementedBy field on it, the TypeContext has to be sent for Common.Route to work.

An important consideration about the return object:

  • The method returns null if the navigations are not modal.
  • The method returns null if the user presses cancel.
  • The method returns the entity modified otherwise (same instance or a new one depending on the Clone option).

Finally, the simplified overload:

//Simplified overload
public static object View(object entity)

Uses SaveClose buttons when the entity is a Thin Lazy, and uses OkCancel otherwise.

Admin

Admin command allow us to open a AdminWindow to Administrate all the entities of given type.

There's just one overload for Admin method:

public static void Admin(AdminOptions adminOptions)

Currently AdminOptions contains just one property:

 public class AdminOptions : MarkupExtension
 {
     public Type Type {...}
 }

Find

Find allow us to open a SearchWindow over a view defined in the server and identified by a queryName.

There are three overloads for Navigator's Find method, the first one:

//General overload
public static object Find(FindOptions findOptions)

Takes FindOptions class as a parameter. This class contains:

    public class FindOptions : MarkupExtension
    {
        public object QueryName {...}
        public SearchButtons Buttons {...}
        public bool Modal {...}
        public bool SearchOnLoad {...}
        public FilterMode FilterMode {...}
        public List<FilterOptions> FilterOptions {...}
        ...
    }

public enum SearchButtons { OkCancel, //Search for an specific entity in some Entity Control Close //Using SearchWindow as the start of your activity (I.E.: Straight from the main menu) }

public enum FilterMode { Visible, VisibleAndReadOnly, Hidden, AlwaysHidden, }

  • QueryName: The actual name of the view that the Search windows is going to use.
  • Buttons: The buttons that will be used. OkCancel is the default
  • Modal: True if the navigation is modal. The default is true if Buttons == SearchButtons.OkCancel
  • SeachOnLoad: Triggers a search when the SearchWindow/Control is loaded. Useful when the number of rows is expected to be small.
  • FilterMode: Determines how the filters panel are going to be shown.

Also, FilterOptions list allow us to add some default filters in the SearchWindow. This is what each FilterOption uses internally:

    public class FilterOptions: Freezable
    {
        public Column Column {...} //Determined when the search windows is open based on ColumnName. You can usully ignore it. 
        public string ColumnName {...} //The name of the column you want to apply a filter over
        public FilterOperation Operation {...}
        public object Value {...} // DependencyProperty. The actual value to compare with.
        public bool Frozen {...} // True if you want the value and the operation 
    }

public enum FilterOperation // The valid operations depend on the type of the column { EqualTo, DistinctTo, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, Contains, StartsWith, EndsWith, Like, }

Note Value is a dependency property. This is a good idea for binding against other property when using integrated SearchControl

The return object behaves similarly to View method: Returns the object on modal navigations where the user clicks Ok.

The return value is the one from the Entity column (usually a Lazy). See more about this in Search.

Finally, there are also two simple overloads for common scenarios.

//Simplified overload to find an entity given a queryName
public static object Find(object queryName)
{
    return Find(new FindOptions(queryName));   
}

//Convenient for QuickLinks (single filter) public static object Find(object queryName, string columnName, object value) { return Find(new FindOptions(queryName) { SearchOnLoad = true, Buttons = SearchButtons.Close, FilterOptions = new List<FilterOptions> { new FilterOptions { ColumnName = columnName, Operation = FilterOperation.EqualTo, Value = value } }, }); }

Creative Commons License Signum Framework Site by Signum Software is licensed under a Creative Commons Attribution 3.0 License.
Powered by ScrewTurn Wiki version 3.0.5.600.