by Paul Stovell via Paul Stovell on 8/5/2010 1:42:09 PM
I just released some source on Google Code called Observal:
http://code.google.com/p/observal/
Observal was extracted from work on a recent WPF project. In our application, we had a deep hierarchy of view model objects, with some very complicated interrelationships - setting one property over here means adding or removing items from a collection over there - and since WPF applications are so stateful, we had to do it all reactively.
The project home page gives a simple example of how Observal might be used. I'll use the remainder of this post for a deeper example.
Suppose we have an object model to represent an organization chart:
We'll build a view to show and edit a hierarchy of employees, and provide a filter to show a list of items from the hierarchy:
Working with the hierarchy in WPF is easy - we just build a hierarchical object model and bind it to the tree view. We could build that view model using code like this:
public partial class OrgChartWindow : Window { public OrgChartWindow() { InitializeComponent(); var sampleEmployees = new Employee("Ryan Howard", 200000, new Employee("Michael Scott", 130000, new Employee("Dwight Schrute", 80000), new Employee("Jim Halpert", 80000, new Employee("Andy Bernard", 75000, new Employee("Stanley Hudson", 70000), new Employee("Phyllis Lapin", 70000))))); DataContext = new OrgChartViewModel(new[] { sampleEmployees }); } }
That gives us the tree view, ability to add new employees and editing support. But how to we manage the list of employees earning under $100,000?
The "Employees with salary < $100,000" panel is effectively a flattened view of the employee hierarchy. To build it, we'd need to subscribe to the CollectionChanged event on every employee's DirectReports collection, and to subscribe to the PropertyChanged event on every employee.
CollectionChanged
DirectReports
PropertyChanged
Observal makes this trivial. We can make the following addition to our view model:
public OrgChartViewModel(IEnumerable<Employee> employees) { _rootEmployees = new ObservableCollection<Employee>(employees); var observer = new Observer(); observer.Extend(new TraverseExtension()).Follow<Employee>(e => e.DirectReports); observer.Extend(new CollectionExpansionExtension()); observer.Extend(new PropertyChangedExtension()).WhenPropertyChanges<Employee>(x => FilterEmployee(x.Source)); observer.Extend(new ItemsChangedExtension()).WhenAdded<Employee>(FilterEmployee); observer.Add(_rootEmployees); } private void FilterEmployee(Employee employee) { if (employee.Salary < 100000) { if (!FilteredEmployees.Contains(employee)) FilteredEmployees.Add(employee); } else { FilteredEmployees.Remove(employee); } }
The idea behind observal is that there is an Observer, which keeps a list of items being observed. Observers can accept IObserverExtensions, which are notified when items are added or removed. In the example above, we make use of four different extensions:
Observer
IObserverExtensions
TraverseExtension
CollectionExpansionExtension
PropertyChangedExtension
ItemsChangedExtension
Each extension is useful by itself, but they become very powerful when combined together. In this example, we were able to monitor an entire hierarchy of objects, and to react whenever parts of the hierarchy changes. I'd urge you to check out Observal on Google Code and let me know what you think.
Original Post: Observal
The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.