Live views sample application (LiveLinqIssueTracker)
This demo shows how live views can be used to construct entire GUI applications based almost entirely on declarative queries/views and data binding, with little procedural code. It also contains an example of how live views can be used in non-GUI, batch, perhaps server-side processing.
It is a mockup bug/issue tracking application in a fictitious company that produces Shakespeare's plays. The demo comes in three variations, each built on top of a different data store: Collections (uses LiveLinq to Objects), ADO.NET (uses LiveLinq to DataSet) and XML (uses LiveLinq to XML). It uses WinForms data binding, but WPF data binding could be used instead just as well and the live views would be exactly the same.
The data schema contains Products (each product is a Shakespeare's play). Each product has features (which, incidentally, are roles in the play). And there are Issues, in other words, bugs (such as bad acting in a certain scene). Also, there are Employees who are assigned those issues (incidentally, those employees are actors playing those roles), and, an important part of this schema, there are Assignments: every employee is assigned a certain number of features to take care of. These assignments can overlap, meaning that more than one employee can be assigned to a feature.
When we start the application and open the Assigned Issues form, we can see issues assigned to any given employee. The view representing it is (we are giving LiveLinq to DataSet versions of the views here, Objects and XML versions are similar):
from i in _dataSet.Issues.AsLive()
join p in _dataSet.Products.AsLive()
on i.ProductID equals p.ProductID
join f in _dataSet.Features.AsLive()
on new { i.ProductID, i.FeatureID }
equals new { f.ProductID, f.FeatureID }
join e in _dataSet.Employees.AsLive()
on i.AssignedTo equals e.EmployeeID
where i.AssignedTo == employeeID
select new Issue
{
IssueID = i.IssueID,
ProductName = p.ProductName,
FeatureName = f.FeatureName,
Description = i.Description,
AssignedTo = e.FullName
};
It is a non-trivial LINQ query, with joins and filtering, and the demo shows that it is live, dynamic, automatically reacts to changes in data, and that GUI controls such as DataGridView can be bound to it.
For example, if we add an issue in the Add Issue form and assign it to the same employee that is shown in the Assigned Issues form, the list of issues for that employee is automatically updated to include the newly created issue.
The Assigned Issues form also demonstrates the difference between Immediate and Deferred maintenance mode, allowing switching between them with two radio buttons. If we switch to the Deferred mode, meaning update on demand, and add an issue, that change is not immediately reflected in the view; it is reflected only when we request data from that view, for example, by changing the employee and then changing it back.
There is also a (Re)assign Issue form that uses basically the same view, so, without writing code using only live views and data binding, we can do things like assign and reassign issues.
Assigned Issues and (Re)assign Issue forms can be opened in any number of instances side by side. You can experiment with opening several forms like that, re-assigning issues in one of them, and then observe the changes automatically reflected in all others.
The demo also shows some actions more complicated than that, such as how live views can change more than just one row at a time. There is a form called All Issues Concerning an Employee that shows all issues for all features assigned to a particular employee using the following view:
from a in _dataSet.Assignments.AsLive()
join p in _dataSet.Products.AsLive()
on a.ProductID equals p.ProductID
join f in _dataSet.Features.AsLive()
on new { a.ProductID, a.FeatureID }
equals new { f.ProductID, f.FeatureID }
join i in _dataSet.Issues.AsLive()
on new { a.ProductID, a.FeatureID }
equals new { i.ProductID, i.FeatureID }
join e in _dataSet.Employees.AsLive()
on i.AssignedTo equals e.EmployeeID
where a.EmployeeID == employeeID
select new Issue
{
IssueID = i.IssueID,
ProductName = p.ProductName,
FeatureName = f.FeatureName,
Description = i.Description,
AssignedTo = e.FullName
};
Assignments of features to an employee can be changed in a (Re)assign Features form. You can experiment with changing the set of features assigned to an employee and see how the changes, which can be quite massive, automatically occur in the All Issues Concerning an Employee form. And although it's not easy to see with such a small data set (unless you add thousands of issues to it, which likely would be the case in a real-life application), the changes to the views shown in the grids are fast, without delays for re-querying the views and refreshing the entire grid, thanks to the incremental view maintenance algorithms implemented in LiveLinq.
The demo also shows how to create views based on other views and how to create indexes on views, see Live Views How To: Create Views Based on Other Views and Create Indexes on Views, and how to use live views to create non-GUI applications as a set of declarative rules instead of procedural code, see Live Views How To: Use Live Views to Create Non-GUI Applications as a Set of Declarative Rules Instead of Procedural Code.