Introduction
LeftNavigationPanel is a control present in the left margin of an
NormalWindow and a
AdminWindow.
Currently LeftNavigationPanel supports two basic fetaures:
- Notes: User interfaces to attach user notes to any entity.
- QuickLinks: Simple links, similar to the one provided by Windows Explorer, allowing navigation to related entities, show pre-filtered Search window, or any action you want to place there.
The current version is limited to just QuickLinks and Notes as a temporal solution, but our plan is to provide a more expandable solution in the near future.
Notes
Notes subsystem allows us to attach post-it like notes to, potentially, any entity. This is useful for the kind of details the end user cares about, that are hard to normalize and are not expected to be in any report.
Unfortunately, notes is a very vertical concept affecting entities, database, service and user interface, so to enable it is slightly cumbersome. In order to add notes to your application just do the following:
1. Choose what entity will store note information. Whatever entity you create has to implement marker interface Signum.Entities.Basics.INote and very likely it will need a ImplementedByAll field referencing the entity it's attached to. To make things simple we already provide a basic NoteDN in the same namespace:
[Serializable]
public class NoteDN : IdentifiableEntity, INoteDN
{
[ImplementedByAll]
Lazy<IdentifiableEntity> entity;
public Lazy<IdentifiableEntity> Entity
{
get { return entity; }
set { Set(ref entity, value, "Entity"); }
}
[NotNullable, SqlDbType(Size = int.MaxValue)]
string text;
[StringLengthValidator(Min = 1)]
public string Text
{
get { return text; }
set { Set(ref text, value, "Text"); }
}
public override string ToString()
{
return text.Etc(200);
}
}
2. Include Note in your
Schema and synchronize the database (or create it again) appropriately.
sb.Include<NoteDN>();
3. Add the EntitySettings mapping line in your Navigator to associate the opportune control, if you are using NoteDN, Signum.Windows.Basics.Note control is already built for you.
{typeof(NoteDN), new EntitySettings(false){ View = ()=>new Note(), IsCreable = admin=>false}},
4. Add a method to retrieve the notes for a given entity in your service, we usually do it like this:
[OperationContract, NetDataContract]
List<Lazy<INoteDN>> RetrieveNotes(Lazy<IdentifiableEntity> lazy);
public List<Lazy<INoteDN>> RetrieveNotes(Lazy<IdentifiableEntity> lazy)
{
return Return(MethodInfo.GetCurrentMethod(),
() => (from n in Database.Query<NoteDN>()
where n.Entity == lazy
select n.ToLazy<INoteDN>()).ToList());
}
5. Configure NotesProviderManager to let it know how to attach a NoteDN to an entity and how to retrieve them from server.
NotesProvider.Manager = new NotesProviderManager
{
CreateNote = ei => ei.IsNew ? null : new NoteDN { Entity = ei.ToLazy() },
RetrieveNotes = ei => ei is INoteDN || ei.IsNew ? null : ServerBugs.Current.RetrieveNotes(ei.ToLazy())
};
The end result is that you can attach notes to every entity now!:

QuickLinks
Another panel you can add at the left side of your entities is QuickLinks panel. QuickLinks are useful to have a unified way of showing actions and, more often, 'backwards relationships' to other entities. Let's explain that:
As we see in
Signum.Entities one important difference between OOP and relational databases is that one uses directed relationships (references) while the other uses symmetric relationships (foreign keys).
Due to that, in a OOP world, if CustomerDN has an AddressDN it's way easier for the customer to go to the Address than the other way around. The CustomerDN, however, could be found with a query on the database. QuickLinks are useful to implement this 'go to parent entities' functionality.
From an architectural point of view, we pick
your custom entity control as the place to define and implement QuickLink instead of
EntitySettings because of the very imperative nature of QuickLinks, and because this way you can have different QuickLinks for different views of your entities. Some future ideas, however, may change the situation...
Let's get to the point:
BugDN has a ProjectDN, but once you are in a project it's kind of unpleasant to go to the related bugs, here we have a niche for a QuickLink! What we do is to make our Project control implement IHaveQuickLinks interface defined like this:
public interface IHaveQuickLinks
{
List<QuickLink> QuickLinks();
}
public class QuickLink
{
public string Label{ get; set; }
public Action Action { get; set; }
public QuickLink(string label)
{
this.Label = label;
}
}
As you may see, to implement IHaveQuickLinks your control needs to return a List of QuickLinks, where a QuickLink is an object with the label that will be shown in the user interface and the action that will be executed when clicked. Obvious isn't it?.
Let's modify out Project control code behind file to implement IHaveQuickLinks:
public partial class Project : UserControl, IHaveQuickLinks
{
public Project()
{
InitializeComponent();
}
public List<QuickLink> QuickLinks()
{
return new List<QuickLink>
{
new QuickLink("Related Bugs")
{
Action = ()=> Navigator.Find(typeof(BugDN), "Project", DataContext)
}
};
}
}
As you see, implementing the interface using
Object and Collection Initializers and a lambda expression for the Action is a piece of cake.
Also note we are using the Navigator.Find overload that takes three parameters, this overload, as shown in
Navigator, sets-up a
Search dialog with a filter and SearchOnLoad = true (since is expected to have just a few results). But since it's an Action, you can do whatever you want, some ideas:
- Make some operations on your current entity, like Close the Project in our example.
- If you know that there will be only related identity, retrieve it from the Server (a custom service operation will do the job) and Navigate to it straight away, skipping the Search window.
The end result of our project control looks (inside of a NormalWindow and an AdminWindow) like this:

And in this case, when you click Related Bugs link, a new
SearchWindow appears, already showing the bugs filtered by Project: