Archive

Archive for the ‘Dependencies’ Category

From Lambda Dependencies to Lambda Bindings

April 3rd, 2009

Lambda-based binding for the business layer or your View Model 🙂

I’ve had this on the shelf for quite a while, but Kent Boogaart’s article on POCOs vs. DependencyObjects finally got me to cleaning things up a little. Kent is coming up with a similar approach that looks very promising, so you should keep your eyes on his blog, too.

Lambda Bindings are built on top of the Lambda Dependencies project I published a while ago. The original Lambda Dependencies allow you to observe object graphs for changes using simple LINQ expressions. Lambda Bindings leverage this pattern by not just publishing a change event but synchronizing target properties or fields automatically.

This provides you with a generic binding framework that can be used wherever you want to synchronize objects. Let’s have a first example:

 

public void TestBinding(Student student)
{
  string cityName = "";

  //synchronize the cityName field with the City property of the school's address
  var binding = LambdaBinding.BindOneWay(
      () => student.School.Address.City,
      () => cityName);

  //change the property on the School object
  student.School.Address.City = "Sin City";

  //the binding expression updated the local variable
  Assert.AreEqual("Sin City", cityName);
}

What’s happening in the snippet above is that I created a binding between a nested property of a referenced object and a local field. As soon as the binding source (the City property of a school’s address) is changed, the local cityName field is being updated as well.

 

However, the Lambda Dependencies not only cover the source properties but the whole object graph. Accordingly, exchanging the whole School (or the Student instance) also triggers an update. In the snippet below, the cityName variable is being updated twice:

 

[Test]
public void Updating_Intermediary_Object_Should_Update_Target(Student student)
{
  string cityName = "";

  //synchronize the cityName field with the City property of the school's address
  var binding = LambdaBinding.BindOneWay(
      () => student.School.Address.City,
      () => cityName);


  //change bound City property -> triggers update of the local variable
  student.School.Address.City = "Paris";
  Assert.AreEqual("Paris", cityName);

  //create a completely different school instance
  School englishSchool = new School();
  englishSchool.Address = new Address {City = "London"};

  //assign the new school to the student
  student.School = englishSchool;

  //setting the School property also triggered the binding
  Assert.AreEqual("London", cityName);
}

 

Value Conversion

You can do simple value conversion by just submitting a converter to the binding expression. This allows you to intercept the binding pipeline or bind objects of different types together. If you’re coming from WPF, this feels natural anyway, but the solution here does not require you to implement a value converter – a simple Func<TSource, TTarget> is sufficient.

Here’s a simple sample that performs a conversion of a boolean flag to into a corresponding Visibility enum value:

 

[Test]
public void Boolean_Should_Be_Converted_To_Visibility()
{
  //create a hidden window
  Window window = new Window { Visibility = Visibiliy.Collapsed };
  
  //create a view model
  MyViewModel viewModel = new MyViewModel { IsVisible = false };
  
  //create binding that casts the Visibility into a boolean
  LambdaBinding.BindOneWay(
      () => viewModel.IsVisible,
      () => window.Visibility,
      b => b == true ? Visibility.Visible : Visibility.Collapsed;
  
  //a change in the ViewModel shows/hides the window
  viewModel.IsVisible = true;
  
  Assert.AreEqual(Visibility.Visible, window.Visibility);  
}

 

Two-Way-Binding

Two way binding works too, of course:

[Test]
public void Updates_Should_Work_Both_Ways()
{
  //create two-way binding
  var binding = LambdaBinding.BindTwoWay(
    () => FirstStudent.Name,
    () => SecondStudent.Name);

  //change property on source
  FirstStudent.Name = "Peter";
  Assert.AreEqual("Peter", SecondStudent.Name);

  //change property on target
  SecondStudent.Name = "Parker";
  Assert.AreEqual("Parker", FirstStudent.Name);
}

In case you need to perform type conversion, you need to supply two converter functions for forward / reverse conversion:

//bind a boolean property to a control's Visibility property
var binding = LambdaBinding.BindTwoWay(
    () => ModelItem.IsEnabled,
    () => MyControl.IsVisible,
    b => b == true ? Visibility.Visible : Visibiliy.Collapsed
    v => v == Visibility.Visible ? true : false);

 

Default Values

In case the object graph is being broken (e.g. because the School was set to null), the target node will be automatically set to its default value (null for an object, 0 for an int etc.). However, you can also specify a default value of your own:

//a local field to be updated
private string schoolCity;

[Test]
public void Breaking_The_Chain_Should_Assign_Default_Value_To_Target_If_Specified()
{
  var binding = LambdaBinding.BindOneWay(
      () => Student.School.Address.City,
      () => schoolCity,
      "[No City]");

  //break the source chain
  Student.School = null;

  //the default value was assigned to the target
  Assert.AreEqual("[No City]", schoolCity);
}

(btw: the above snippet also shows you that you can easily bind to a field rather than a property).

 

Weak References

The underlying Lambda Dependencies only use weak references so you’re not at risk of creating memory leaks. However, LambdaBinding implements IDisposable, so the proper way to clean things up would be to dispose your binding.

Things to Consider

Remember that that the underlying Lambda Dependencies rely on the INotifyPropertyChanged interface, so don’t expect source binding to fields (or properties that do not fire a PropertyChanged event) to magically update your targets.

 

Download: lambda-dependencies.zip

 

kick it on DotNetKicks.com

Lambda Dependencies Update

December 30th, 2008

I just uploaded an update of my Lambda Dependencies library which fixes a bug with the weak event proxy. The update contains the fix and some minor optimizations.

Lambda Dependencies 1.0.1: dependencies.zip

Author: Categories: Dependencies Tags:

Tracking Inter-Object Dependencies using Expression Trees (Part 2)

December 28th, 2008

This is the second part of an article that covers the usage of lambda expressions to monitor changes on complex object graphs. The first part can be found here and the third part (Lambda Binding) is here.

Latest Version: 1.0.3, 2009.04.03
Download Project: lambda-dependencies.zip

Introduction

 

The first part covered the basics of the framework based on a sample application where I monitored any changes on the object graph MyStudent.School.Address.City with a simple lambda expression:

public MyApplication()
{
  //create a dependency on the city of the student's school
  var dep = DependencyNode.Create(() => MyStudent.School.Address.City);
}

 

The subsequent chapters discuss a few advanced topics that might be important when working with the API.

 

INotifyPropertyChanged vs. Manual Updates

In order to pick up a changed values on the dependency chain, the observed classes (in the sample: School, Student, Address) must implement the INotifyPropertyChanged interface. Otherwise, changes remain undetected.

This might not be a problem in case of immutable properties or fields, and it is perfectly valid to include classes that do not implement the interface. However: In case you don’t have INotifyPropertyChanged available (e.g. because you rely on a class in an external library), and changes do occur, you can manually update these node values by invoking the SetNodeValue method of an arbitrary dependency node.

public void SetFieldDependency()
{
  Student student = TestUtil.CreateTestStudent();

  //create dependency on the address field rather than the Address property
  var dep = DependencyNode.Create(() => student.School.address.City);
  dep.DependencyChanged +=
      (node, e) => Console.WriteLine("City: " + e.TryGetLeafValue());

  //exchange address
  var newAddress = new Address {City = "Stockholm"};
  student.School.address = newAddress;

  //get the node that represents the address
  var addressFieldNode = dep.FindNode(() => student.School.address);

  //set the node value manually and trigger change event
  addressFieldNode.SetNodeValue(newAddress, true);
}

 

Reacting to Sub Property and Target Collection Changes

In the sample above, we declared a dependency on the City property of an Address object. City is just a string, but what if we wanted to track *any* change on the school’s address? One way would be to declare dependencies for every single property of the address:

var student = TestUtil.CreateTestStudent("Harvard");

//create dependency on City
var dep1 = DependencyNode.Create(() => student.School.Address.City);
//create dependency on Street
var dep2 = DependencyNode.Create(() => student.School.Address.Street);
//...

 

This, however, is pretty tedious and there is a simpler solution: As Address implements INotifyPropertyChanged, we can just declare a dependency on the Address property of School.

var student = TestUtil.CreateTestStudent("Harvard");

//create dependency on address object
var dep1 = DependencyNode.Create(() => student.School.Address);

//output the changed property name and the change reason
dep1.DependencyChanged += (node, e) =>
      {
        string msg = "Changed property: {0}, change reason: {1}";
        Console.Out.WriteLine(msg, e.ChangedMemberName, e.Reason);
      };

//change the city
student.School.Address.City = "Ethon";

 

The above snippet registers with the DependencyChanged event and writes two properties of the event’s DependencyChangeEventArgs to the console: ChangedMemberName and the Reason. This produces the following console output:

Changed property: City, change reason: SubPropertyChanged

 

Note that this is a special case: The declared dependency chain is Student:School:Address while we received a change event for the City property, which is not part of the dependency chain!

I think that usually, this is a desired behavior, so this is the default. However, you can control this behavior by using a DependencyNodeSettings class and explicitly setting the ObserveSubValueChanges property:

var student = TestUtil.CreateTestStudent("Harvard");

//create settings class
var settings = new DependencyNodeSettings<Address>(() => student.School.Address);
settings.ChangeHandler = OnDependencyChanged;

//configure settings to ignore sub item changes
settings.ObserveSubValueChanges = false;

//does not cause a change event:
Student.School.Address.City = "Ethon";

 

Note that the same behavior goes for target items that are collections. If the target collection implements the INotifiyCollectionChanged interface, the dependency node fires the DependencyChanged event with a reason of TargetCollectionChange as soon as the contents of the targeted collection changes.

Weak References (and Deserved Credits)

A DependencyNode only maintains weak references. Even if it would not pick up an object that goes out of scope because no property change event was fired, this still wouldn’t stop the targeted object from being garbage collected. The same goes for node’s events and internal event listeners.

I’m using two very nice implementations for internal listeners and the exposed DependencyChanged event:

 

Limitations

This library solves a specific problem and currently operates solely on members, variables, and constant expressions – more complex expressions (such as LINQ queries) are currently out of the picture, but I’m open to suggestions. You might also look out for related projects, such as Bindable LINQ.

Author: Categories: C#, Dependencies Tags: ,

Tracking Inter-Object Dependencies using Expression Trees (Part 1)

December 28th, 2008

This is the first part of an article that covers the usage of lambda expressions to monitor changes on complex object graphs.

The second part can be found here.
The third part (Lambda Bindings) can be found here.

 

Latest Version: 1.0.3, 2009.04.03
Download Project: lambda-dependencies.zip

Introduction

In an ongoing project, I had to struggle with quite a few dependencies between objects, mainly with regards to validation. As a result, I came up with a generic solution based on lambda expressions.

But let’s start with an example. Imagine you have an application that references a Student that attends a a given School. And let’s assume, the school’s location (city) is of importance to you, so a changed city should trigger some action. My class model looks like this:

image

 

In order to keep track of the dependency on the school’s location, you have to observe quite a few things:

  • Whether the City property of the school’s Address object is changed.
  • Whether the Address object of the school itself is replaced by another instance.
  • Whether the referenced School object of the student is changed. This would require you to re-wire change listeners for the school and address.
  • Whether the referenced student instance itself is being replaced by setting the MyStudent property. Again, you would have to deregister all existing listeners and create new ones for the new student, school, and address.

 

This is a lot of error-prone and tedious work: You need to register and de-register event listeners, handle null references (a new School instance might not provide an Address at first) etc. This is where expression trees come to the rescue. Basically, you can reduce the plumbing to a single line of code:

 

public MyApplication()
{
  //create a dependency on the city of the student's school
  DependencyNode<string> dependency;
  dependency = DependencyNode.Create(() => MyStudent.School.Address.City);
}

 

The snippet above analyzes the submitted expression and resolves the dependency graph, which basically looks the following:

image

Dependency.Create returns an object of type DependencyNode. This node refers to the root of the expression tree, which is the MyApplication class that provides the MyStudent property. You can traverse the dependency chain in both directions through  the ChildNode and ParentNode properties should you ever want to. But usually (if at all!), you’ll need just two properties:

  • LeafValue returns the dependency target. In our sample, this is the string that is returned by the City property of the school’s Address.
  • If the school’s Address (or the School reference itself) would be set to null, there would not be a city at all. In this case, LeafValue just returns a value of null. However: You can check whether the graph from root to the dependency target is intact by evaluating the IsChainBroken property on any given node.

 

//get the city, if the dependency graph leads to a valid address
string city = dependency.IsChainBroken ? "NONE" : dependency.LeafValue;

(Note that LeafValue is a generic property. In this case, it is of type string)

image

 

Handling Changes in the Dependency Chain

As soon as a dependency is declared, the DependencyNode tries to register event listeners on all objects of the dependency graph in order to track changes and keep itself up-to-date. Furthermore, you can register an event listener with the node’s DependencyChanged event, which fires whenever a change in the dependency chain occurs. Event listeners receive an instance of DependencyChangeEventArgs that provide the changed node, property or field names, and the change reason:

image

 

Here’s a sample – the snippet below registers an event listener which basically just outputs the name of the student, the school name, and the city to the console:

 

public MyApplication()
{
  //create a dependency on the city of the student's school
  dependency = DependencyNode.Create(() => MyStudent.School.Address.City);
  dependency.DependencyChanged += OnStudentCityChanged;
}


/// <summary>
/// Invoked whenever the dependency graph between <see cref="MyStudent"/>
/// property and the <see cref="Address.City"/> of the student's
/// school is being changed.
/// </summary>
private void OnStudentCityChanged(object sender, DependencyChangeEventArgs<string> e)
{
  //get the changed node
  DependencyNode<string> changedNode = e.ChangedNode;

  //get student name, if we have one after all
  string studentName = myStudent == null ? "[none]" : myStudent.Name;

  //get the school name
  string school = "[none]";
  if (myStudent != null && myStudent.School != null)
  {
    school = myStudent.School.SchoolName;
  }

  //get the city, if the dependency graph leads to a valid address
  string city = changedNode.IsChainBroken ? "[unavailable]" : changedNode.LeafValue;

  //NOTE: You can also get the leaf value through this convenience method:
  //string city = e.TryGetLeafValue("[unavailable]");

  //write student/city to console
  string msg = "Student {0} goes now to school {1} in {2}";
  Console.Out.WriteLine(msg, studentName, school, city);
}

 

Once an event listener is registered, you can change properties on different levels of the dependency chain:

public void Test()
{
  //assign a student
  MyStudent = new Student { Name = "Lucy" };
  //set a school without an address
  MyStudent.School = new School {SchoolName = "University"};
  //assign an address
  MyStudent.School.Address = new Address {City = "Redmond"};
  //assign another address instance
  MyStudent.School.Address = new Address {City = "New York"};
  //change the City property of the address
  MyStudent.School.Address.City = "Washington";
  //cut the graph by removing the school reference
  MyStudent.School = null;
  //clear the MyStudent property completely
  MyStudent = null;
}

 

Every line of the above test method triggers the change event. Accordingly, the console output is the following:

Student Lucy goes now to school [none] in [unavailable]
Student Lucy goes now to school University in [unavailable]
Student Lucy goes now to school University in Redmond
Student Lucy goes now to school University in New York
Student Lucy goes now to school University in Washington
Student Lucy goes now to school [none] in [unavailable]
Student [none] goes now to school [none] in [unavailable]

 

Enjoy 🙂

kick it on DotNetKicks.com

Author: Categories: C#, Dependencies Tags: ,