Archive

Posts Tagged ‘.NET’

Attached Behaviors Part 7: EnumSelector

April 28th, 2011 No comments

Last time, we explored the concept of a user making a choice between various enumeration values. We implemented the choice as a set of radio buttons, where each represents a different value and all are bound to the same property. Radio buttons are one of many controls which allow the user to select from various choices. There is a family of controls, such as ComboBox and ListBox, which inherit their selection capabilities from a common primitive, the Selector control. In this installment, we will write an attached behavior to select an enumeration value from any implementation of Selector.

Scenario

Selectors have two important elements: a collection of child objects, and a currently selected object out of that collection. This mimics a choice between enumeration values quite nicely. For example, a checkout form might offer multiple payment methods, such a credit card or PayPal, and allow the user to choose with a combo box. Here, we can use enumeration matching to synchronize a property with the selected item:

<ComboBox local:EnumSelector.SelectedValue="{Binding PaymentType, Mode=TwoWay}">

  <ComboBoxItem Content="Credit card" local:EnumSelector.ItemValue="CreditCard" />

  <ComboBoxItem Content="PayPal" local:EnumSelector.ItemValue="PayPal" />

</ComboBox>

The combo box’s selected value is bound to the PaymentType property and each item is associated with an enumeration value. When the user changes the selection, the attached behavior writes the selected value to the PaymentType property through a two-way binding.

NOTE: The current incarnation of this behavior requires a ComboBoxItem for each value. This is because the items in the selector must have the ItemValue attached property set directly on them. If we place, say, a TextBox directly within the ComboBox, and set the ItemValue property on it, the ComboBox will generate a ComboBoxItem for us, but it won’t have the ItemValue property set. We might be able to check the Content property of each ComboBoxItem for ItemValue, but that is for a future iteration.

EnumSelector

Once again, we define the behavior as a static class:

public static class EnumSelector

Next, we register the attached properties which govern the behavior. First is the SelectedValue property, which can contain any enumeration value and thus needs to be typed as object. We also create static accessors to facilitate XAML usage:

public static readonly DependencyProperty SelectedValueProperty =

  DependencyProperty.RegisterAttached(

    "SelectedValue",

    typeof(object),

    typeof(EnumSelector),

    new PropertyMetadata(OnSelectedValueChanged));

 

public static object GetSelectedValue(Selector selector)

{

  return selector.GetValue(SelectedValueProperty);

}

 

public static void SetSelectedValue(Selector selector, object value)

{

  selector.SetValue(SelectedValueProperty, value);

}

Then, we register the ItemValue property, which is a simple string we will parse later:

public static readonly DependencyProperty ItemValueProperty =

  DependencyProperty.RegisterAttached(

    "ItemValue",

    typeof(string),

    typeof(EnumSelector),

    new PropertyMetadata(OnItemValueChanged));

 

public static string GetItemValue(DependencyObject item)

{

  return (string) item.GetValue(ItemValueProperty);

}

 

public static void SetItemValue(DependencyObject item, string value)

{

  item.SetValue(ItemValueProperty, value);

}

Behavior

The nice part about the attached behavior framework is that most of the code which goes into behaviors is fairly boilerplate. First, we declare the behavior and tell it how to create instances for individual host objects:

private static readonly AttachedBehavior Behavior =

  AttachedBehavior.Register(host => new EnumSelectorBehavior(host));

Then, we update it when the SelectedValue dependency property changes:

private static void OnSelectedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

  Behavior.Update(d);

}

This attached behavior has an extra step, though: we need to update the behavior not only when SelectedValue changes on the selector, but also when ItemValue changes on any item:

private static void OnItemValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

  var item = d as FrameworkElement;

 

  if(item != null)

  {

    var selector = item.Parent as Selector;

 

    if(selector != null)

    {

      Behavior.Update(selector);

    }

  }

}

The behavior implementation is also more involved. The previous enumeration matching behaviors each had one match to perform; this behavior, however, has one match per item. This adds a some complexity but not much.

The class declaration is similar to other behaviors:

private sealed class EnumSelectorBehavior : Behavior<Selector>

As is the constructor:

internal EnumSelectorBehavior(DependencyObject host) : base(host)

{}

The first major difference is that we store an index associating items with their enumeration checks:

private readonly IDictionary<object, EnumCheck> _itemEnumChecks =

  new Dictionary<object, EnumCheck>();

The Attach and Detach overrides manage a handler for the selector’s SelectionChanged event:

protected override void Attach(Selector host)

{

  host.SelectionChanged += OnSelectionChanged;

}

 

protected override void Detach(Selector host)

{

  host.SelectionChanged -= OnSelectionChanged;

 

  _itemEnumChecks.Clear();

}

In the Detach method, we make sure to remove all references to items and their associated enumeration checks.

The Update method goes through all of the items, updates the enumeration check associated with each one, and sets the selector’s SelectedIndex property to the first one which matches:

protected override void Update(Selector host)

{

  var selectedValue = GetSelectedValue(host);

 

  for(var index = 0; index < host.Items.Count; index++)

  {

    var item = host.Items[index];

 

    var itemEnumCheck = GetItemEnumCheck(item);

 

    itemEnumCheck.Update(selectedValue, GetItemValue(item));

 

    if(itemEnumCheck.IsMatch)

    {

      host.SelectedIndex = index;

 

      break;

    }

  }

}

The GetItemEnumCheck method gets the EnumCheck associated with the specified item. If one doesn’t yet exist, we create and cache it:

private EnumCheck GetItemEnumCheck(object item)

{

  EnumCheck itemEnumCheck;

 

  if(!_itemEnumChecks.TryGetValue(item, out itemEnumCheck))

  {

    itemEnumCheck = new EnumCheck();

 

    _itemEnumChecks[item] = itemEnumCheck;

  }

 

  return itemEnumCheck;

}

The GetItemValue method is a bit of glue which attempts to convert an item to a DependencyObject and, if successful, accesses its ItemValue attached property:

private static string GetItemValue(object item)

{

  var dependencyObjectItem = item as DependencyObject;

 

  return dependencyObjectItem == null

    ? null

    : EnumSelector.GetItemValue(dependencyObjectItem);

}

These methods implement the updating of the selector based on the SelectedValue and ItemValue attached properties.

The other side of the coin, updating the SelectedValue attached property when the selector changes, is implemented by the OnSelectionChanged event handler. We again use the TryUpdate method, passing it the name of another method, UpdateSelectedValue, which will only be invoked if the host object hasn’t been garbage-collected:

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)

{

  TryUpdate(UpdateSelectedValue);

}

The UpdateSelectedValue method updates the enumeration check associated with the selected item and updates the SelectedValue attached property of the host with the selected item’s value:

private void UpdateSelectedValue(Selector host)

{

  var selectedValue = GetSelectedValue(host);

 

  var itemEnumCheck = GetItemEnumCheck(host.SelectedItem);

 

  itemEnumCheck.Update(selectedValue, GetItemValue(host.SelectedItem));

 

  var parsedTargetValue = itemEnumCheck.ParsedTargetValue;

 

  if(selectedValue != null && !selectedValue.Equals(parsedTargetValue))

  {

    SetSelectedValue(host, parsedTargetValue);

  }

}

The if statement prevents an infinite loop where an update to the SelectedValue property raises the SelectionChanged event which updates the SelectedValue property which raises the SelectionChanged event, etc.

Sample Project

This WPF project shows EnumSelector in action:

Attached Behaviors Part 7 EnumSelector.zip

It allows you to set the value of the EnumSelector.SelectedValue attached property and see the results when applied to a ListBox. You can also selected different items in the ListBox and see EnumSelector.SelectedValue change, showing the effect of the two-way binding.

Summary

We used enumeration matching to allow the user to select an enumeration value from many. Like radio buttons, selectors naturally represent a choice between mutually exclusive values. The behavior can be applied to anything which implements Selector, offering a large amount of flexibility and extensibility.

What Next?

These are all the attached behaviors I have for now. They cover the various situations I have encountered in my XAML-related career, mostly in an MVVM context. I am sure I will discover more, though, so I will post write-ups when I do.

My personal utilities library, Cloak, contains the framework as well as all the behaviors featured in this series, for both WPF and Silverlight. (There is a lot of other goodness in there as well.) Download it and give them a try!

(If you found this series useful or maybe even enjoyed it, leave a comment. It’s always nice to be reminded I’m not writing in a void.)

Attached Behaviors Part 6: EnumGroup

April 26th, 2011 No comments
    Our framework for matching enumeration values has helped us easily manage the Visibility and IsEnabled properties of individual controls. Now, we will write an attached behavior to select a value from a set of radio buttons.

    Scenario

    Radio buttons naturally represent an enumeration: as a related set of controls, known as a group, each is a value in a mutually exclusive selection. For example, a checkout form might offer multiple payment methods, such a credit card or PayPal, and allow the user to choose with radio buttons. Here, we can use enumeration matching to synchronize a property with the selected radio button:

<RadioButton

  Content="Credit card"

  local:EnumGroup.Value="{Binding PaymentType, Mode=TwoWay}"

  local:EnumGroup.TargetValue="CreditCard"

/>

<RadioButton

  Content="PayPal"

  local:EnumGroup.Value="{Binding PaymentType, Mode=TwoWay}"

  local:EnumGroup.TargetValue="PayPal"

/>

Each radio button is associated with an enumeration value. When the user selects an option, it writes that value to the PaymentType property through a two-way binding.

EnumGroup

If you have read the rest of the series, there isn’t much new here. We define the behavior as a static class:

public static class EnumGroup

Next, we register the attached properties which govern the behavior. First is the Value property, which can contain any enumeration value and thus needs to be typed as object. We also create static accessors to facilitate XAML usage:

public static readonly DependencyProperty ValueProperty =

  DependencyProperty.RegisterAttached(

    "Value",

    typeof(object),

    typeof(EnumGroup),

    new PropertyMetadata(OnArgumentsChanged));

 

public static object GetValue(RadioButton radioButton)

{

  return radioButton.GetValue(ValueProperty);

}

 

public static void SetValue(RadioButton radioButton, object value)

{

  radioButton.SetValue(ValueProperty, value);

}

Then, we register the TargetValue property, which is a simple string we will parse later:

public static readonly DependencyProperty TargetValueProperty =

  DependencyProperty.RegisterAttached(

    "TargetValue",

    typeof(string),

    typeof(EnumGroup),

    new PropertyMetadata(OnArgumentsChanged));

 

public static string GetTargetValue(RadioButton radioButton)

{

  return (string) radioButton.GetValue(TargetValueProperty);

}

 

public static void SetTargetValue(RadioButton radioButton, string value)

{

  radioButton.SetValue(TargetValueProperty, value);

}

Behavior

The integration of the behavior into the static class is exactly the same as the previous behaviors. First, we declare the behavior and tell it how to create instances for individual host objects:

private static readonly AttachedBehavior Behavior =

  AttachedBehavior.Register(host => new EnumGroupBehavior(host));

Then, we update it when either of the Value or TargetValue dependency properties changes:

private static void OnArgumentsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

  Behavior.Update(d);

}

The behavior class is more interesting than those for other behaviors because it overrides the Attach and Detach methods to manage a handler for the Checked event:

private sealed class EnumGroupBehavior : Behavior<RadioButton>

{

  private readonly EnumCheck _enumCheck = new EnumCheck();

 

  internal EnumGroupBehavior(DependencyObject host) : base(host)

  {}

 

  protected override void Attach(RadioButton host)

  {

    host.Checked += OnChecked;

  }

 

  protected override void Detach(RadioButton host)

  {

    host.Checked -= OnChecked;

  }

 

  protected override void Update(RadioButton host)

  {

    _enumCheck.Update(GetValue(host), GetTargetValue(host));

 

    host.IsChecked = _enumCheck.IsMatch;

  }

 

  private void OnChecked(object sender, RoutedEventArgs e)

  {

    TryUpdate(host => SetValue(host, _enumCheck.ParsedTargetValue));

  }

}

The Update method, called whenever Value or TargetValue changes (via OnArgumentsChanged), is straightforward. We leverage the EnumCheck class to manage the parsing, caching, and matching. Then, we set the IsChecked property based on whether Value matches TargetValue.

Another interesting aspect of this behavior is the handler for the radio button’s Checked event. This is the first time we have a chance to use the TryUpdate method, which executes the specified lambda expression only if the host has not been garbage-collected.

The Checked event occurs when the radio button becomes the selected value in its group. When that happens, we set the Value property to the associated target value. Voila!

Sample Project

This WPF project shows EnumGroup in action:

Attached Behaviors Part 6 EnumGroup.zip

It allows you to set the value of the EnumGroup.Value attached property and see the results when applied to two radio buttons. You can also check the radio buttons and see EnumGroup.Value change, showing the effect of the two-way binding.

As a side note, the EnumCheck class evolved since the last post. It now performs the duties of EnumTargetValue, which no longer exists. It also has a new member, ParsedTargetValue, which we used in the OnChecked method above. It returns the first value from ParsedTargetValues, which may contain multiple values if TargetValue is set to a comma-separated string.

Summary

We used enumeration matching to put another fundamental building block in place, the radio button group. Their mutually exclusive nature is a seamless fit for selecting one value from many. By associating each radio button with an enumeration value, we easily and intuitively described a choice.

Next time, we will use selectors, such as a combo boxes and list boxes, to select enumeration values.

Attached Behaviors Part 5: EnumIsEnabled

February 23rd, 2011 No comments

Last time, we created a small framework for matching enumeration values. With this very handy technique in our arsenal, we can start interpreting enumeration properties in various ways.

Scenario

A common situation is the need to enable and disable related sets of controls. For example, we might disable credit card fields if a user chooses the PayPal option on a checkout form (and vice versa). In these cases, we can use enumeration matching to manage the UIElement.IsEnabled property:

<StackPanel>

  <local:PayPalOptions

    local:EnumIsEnabled.Value="{Binding PaymentType}"

    local:EnumIsEnabled.TargetValue="PayPal"

  />

  <local:CreditCardOptions

    local:EnumIsEnabled.Value="{Binding PaymentType}"

    local:EnumIsEnabled.TargetValue="CreditCard"

  />

</StackPanel>

Both of the payment options are governed by the PaymentType property. They are mutually exclusive because only one target value will match at a time.

Like with other enumeration-based behaviors, we can invert the results of the match using the WhenMatched and WhenNotMatched properties:

<local:CreditCardOptions

  local:EnumIsEnabled.Value="{Binding PaymentType}"

  local:EnumIsEnabled.TargetValue="CreditCard"

  local:EnumIsEnabled.WhenMatched="False"

  local:EnumIsEnabled.WhenNotMatched="True"

/>

EnumIsEnabled

The naming for this concept is a little fuzzy. My first thought, EnumEnabler, uses a term most commonly associated with addictive behavior. Scratch. EnumEnabled is closer, but it sounds like we are enabling something about enumerations, not setting the IsEnabled property. I ultimately decided the format EnumPropertyName is more discoverable than using an arbitrary term to complete the identifier. Naming suggestions are welcome in the comments.

The process of defining an attached behavior should be very familiar by now. We start by declaring a static class:

public static class EnumIsEnabled

Next, we register the attached properties which govern the behavior. First is the Value property, which can contain any enumeration value and thus needs to be typed as object. We also create static accessors to facilitate XAML usage:

public static readonly DependencyProperty ValueProperty =

  DependencyProperty.RegisterAttached(

    "Value",

    typeof(object),

    typeof(EnumIsEnabled),

    new PropertyMetadata(OnArgumentsChanged));

 

public static object GetValue(UIElement uiElement)

{

  return uiElement.GetValue(ValueProperty);

}

 

public static void SetValue(UIElement uiElement, object value)

{

  uiElement.SetValue(ValueProperty, value);

}

Next, we register the TargetValue property, which is a simple string we will parse later:

public static readonly DependencyProperty TargetValueProperty =

  DependencyProperty.RegisterAttached(

    "TargetValue",

    typeof(string),

    typeof(EnumIsEnabled),

    new PropertyMetadata(OnArgumentsChanged));

 

public static string GetTargetValue(UIElement uiElement)

{

  return (string) uiElement.GetValue(TargetValueProperty);

}

 

public static void SetTargetValue(UIElement uiElement, string value)

{

  uiElement.SetValue(TargetValueProperty, value);

}

Then, we register the WhenMatched property, giving it a default value of true:

public static readonly DependencyProperty WhenMatchedProperty =

  DependencyProperty.RegisterAttached(

    "WhenMatched",

    typeof(bool),

    typeof(EnumIsEnabled),

    new FrameworkPropertyMetadata(true, OnArgumentsChanged));

 

public static bool GetWhenMatched(UIElement uiElement)

{

  return (bool) uiElement.GetValue(WhenMatchedProperty);

}

 

public static void SetWhenMatched(UIElement uiElement, bool value)

{

  uiElement.SetValue(WhenMatchedProperty, value);

}

Finally, we register the WhenNotMatched property, giving it a default value of false:

public static readonly DependencyProperty WhenNotMatchedProperty =

  DependencyProperty.RegisterAttached(

    "WhenNotMatched",

    typeof(bool),

    typeof(EnumIsEnabled),

    new FrameworkPropertyMetadata(false, OnArgumentsChanged));

 

public static bool GetWhenNotMatched(UIElement uiElement)

{

  return (bool) uiElement.GetValue(WhenNotMatchedProperty);

}

 

public static void SetWhenNotMatched(UIElement uiElement, bool value)

{

  uiElement.SetValue(WhenNotMatchedProperty, value);

}

Behavior

As in the previous installments in this series, we declare the behavior, telling it how to create instances for individual host objects:

private static readonly AttachedBehavior Behavior =

  AttachedBehavior.Register(host => new EnumIsEnabledBehavior(host));

Now, we update it whenever any of the above dependency properties changes:

private static void OnArgumentsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

  Behavior.Update(d);

}

The behavior implementation looks almost exactly like the one for EnumVisibility:

private sealed class EnumIsEnabledBehavior : Behavior<UIElement>

{

  private readonly EnumCheck _enumCheck = new EnumCheck();

 

  internal EnumIsEnabledBehavior(DependencyObject host) : base(host)

  {}

 

  protected override void Update(UIElement host)

  {

    _enumCheck.Update(GetValue(host), GetTargetValue(host));

 

    host.IsEnabled = _enumCheck.IsMatch

      ? GetWhenMatched(host)

      : GetWhenNotMatched(host);

  }

}

We once again leverage the EnumCheck class to manage the parsing, caching, and matching of target values.

Sample Project

This WPF application shows EnumIsEnabled in action:

Attached Behaviors Part 5 EnumIsEnabled.zip

It allows you to set the value of the EnumIsEnabled.Value attached property on three different text blocks. The first shows when Value matches TargetValue. The second shows when Value matches a comma-separated TargetValue. The third uses the WhenMatched and WhenNotMatched attached properties to show when Value does not match TargetValue instead.

Summary

Except for the reference to the IsEnabled property, we didn’t really write anything new for this attached behavior. We only have to write code at all because the Value, TargetValue, WhenMatched, and WhenNotMatched properties must be scoped to a specific class in the XAML. This, along with the fact that WhenMatched and WhenNotMatched can have different types, is why we redeclare the properties on each new behavior.

Next time, we will use a group of radio buttons to allow the user to select enumeration values.

Attached Behaviors Part 4: EnumVisibility

February 15th, 2011 No comments

Another convenient behavior is to conditionally show a piece of UI based on the value of an enumeration property. This is especially useful for working with view models in an MVVM context, where enumerations are a common property type.

The input to this behavior is a value and a target value. The host is shown/hidden based on whether they match:

<TextBlock

  Text="Access denied"

  local:EnumVisibility.Value="{Binding UserType}"

  local:EnumVisibility.TargetValue="Standard"

/>

We can specify multiple target values to compare against the Value property:

<TextBlock

  Text="Access granted"

  local:EnumVisibility.Value="{Binding UserType}"

  local:EnumVisibility.TargetValue="Moderator, Administrator"

/>

We can also invert the translation using the WhenMatched and WhenNotMatched properties:

<TextBlock

  Text="Access granted"

  local:EnumVisibility.Value="{Binding UserType}"

  local:EnumVisibility.TargetValue="Standard"

  local:EnumVisibility.WhenMatched="Collapsed"

  local:EnumVisibility.WhenNotMatched="Visible"

/>

An especially nice use is specifying user-friendly names for enumeration values (a traditionally thorny problem). We bind a bank of controls in the same space to the same property, knowing only one will show up at any given time. This gives us maximum flexibility in representing particular enumeration values:

<Grid>

  <TextBlock

    Text="Standard"

    local:EnumVisibility.Value="{Binding UserType}"

    local:EnumVisibility.TargetValue="Standard"

  />

  <TextBlock

    Text="Moderator"

    local:EnumVisibility.Value="{Binding UserType}"

    local:EnumVisibility.TargetValue="Moderator"

    FontWeight="Bold"

  />

  <StackPanel

    local:EnumVisibility.Value="{Binding UserType}"

    local:EnumVisibility.TargetValue="Administrator"

    Orientation="Horizontal">

    <TextBlock Text="Administrator" FontWeight="Bold" />

    <Image Source="admin.jpg" />

  </StackPanel>

</Grid>

This allows us to use bindings, resources, localization, and any other technique to portray user-friendly names.

EnumVisibility

We define the attached behavior as a static class:

public static class EnumVisibility

Next, we register the attached properties which govern the behavior. First is the Value property, which can contain any enumeration value and thus needs to be typed as object. We also create static accessors to facilitate XAML usage:

public static readonly DependencyProperty ValueProperty =

  DependencyProperty.RegisterAttached(

    "Value",

    typeof(object),

    typeof(EnumVisibility),

    new PropertyMetadata(OnArgumentsChanged));

 

public static object GetValue(UIElement uiElement)

{

  return uiElement.GetValue(ValueProperty);

}

 

public static void SetValue(UIElement uiElement, object value)

{

  uiElement.SetValue(ValueProperty, value);

}

Next, we register the TargetValue property, which is a simple string we will parse later:

public static readonly DependencyProperty TargetValueProperty =

  DependencyProperty.RegisterAttached(

    "TargetValue",

    typeof(string),

    typeof(EnumVisibility),

    new PropertyMetadata(OnArgumentsChanged));

 

public static string GetTargetValue(UIElement uiElement)

{

  return (string) uiElement.GetValue(TargetValueProperty);

}

 

public static void SetTargetValue(UIElement uiElement, string value)

{

  uiElement.SetValue(TargetValueProperty, value);

}

Then, we register the WhenMatched property, giving it a default value of Visible:

public static readonly DependencyProperty WhenMatchedProperty =

  DependencyProperty.RegisterAttached(

    "WhenMatched",

    typeof(Visibility),

    typeof(EnumVisibility),

    new FrameworkPropertyMetadata(Visibility.Visible, OnArgumentsChanged));

 

public static Visibility GetWhenMatched(UIElement uiElement)

{

  return (Visibility) uiElement.GetValue(WhenMatchedProperty);

}

 

public static void SetWhenMatched(UIElement uiElement, Visibility visibility)

{

  uiElement.SetValue(WhenMatchedProperty, visibility);

}

Finally, we register the WhenNotMatched property, giving it a default value of Collapsed:

public static readonly DependencyProperty WhenNotMatchedProperty =

  DependencyProperty.RegisterAttached(

    "WhenNotMatched",

    typeof(Visibility),

    typeof(EnumVisibility),

    new FrameworkPropertyMetadata(Visibility.Collapsed, OnArgumentsChanged));

 

public static Visibility GetWhenNotMatched(UIElement uiElement)

{

  return (Visibility) uiElement.GetValue(WhenNotMatchedProperty);

}

 

public static void SetWhenNotMatched(UIElement uiElement, Visibility visibility)

{

  uiElement.SetValue(WhenNotMatchedProperty, visibility);

}

Behavior

Just like with BooleanVisibility and NullVisibility, we declare the behavior, telling it how to create instances for individual host objects:

private static readonly AttachedBehavior Behavior =

  AttachedBehavior.Register(host => new EnumVisibilityBehavior(host));

Now, we update it whenever any of the above dependency properties changes:

private static void OnArgumentsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

  Behavior.Update(d);

}

The IBehavior implementation is similar to the other attached behaviors:

private sealed class EnumVisibilityBehavior : Behavior<UIElement>

{

  private readonly EnumCheck _enumCheck = new EnumCheck();

 

  internal EnumVisibilityBehavior(DependencyObject host) : base(host)

  {}

 

  protected override void Update(UIElement host)

  {

    _enumCheck.Update(GetValue(host), GetTargetValue(host));

 

    host.Visibility = _enumCheck.IsMatch

      ? GetWhenMatched(host)

      : GetWhenNotMatched(host);

  }

}

The major difference is this behavior uses an object dedicated to checking the value against the target value. This cleans up the code considerably, as the matching logic is not trivial. It also allows us to reuse it in other enumeration-related behaviors.

Enumeration Checks

An enumeration check requires parsing of the target value(s) to the enumeration type. Rather than perform the parse every time, the EnumCheck type caches the parsed target values and only recalculates them when necessary. This stateful nature is why we update the _enumCheck field and then query its IsMatch property when updating the behavior.

The EnumCheck class has three properties:

public object Value { get; private set; }

 

public EnumTargetValue TargetValue { get; private set; }

 

public bool IsMatch { get; private set; }

The interesting thing here is the TargetValue property: the EnumTargetValue class encapsulates the parsing and comparison of target value strings. We initialize it in the constructor to an empty instance:

public EnumCheck()

{

  this.TargetValue = new EnumTargetValue();

}

The Update method, which we call from the behavior’s Update method above, is where we coordinate the match:

public void Update(object value, string targetValue)

{

  var valueChanged = value != this.Value;

  var targetValueChanged = targetValue != this.TargetValue.Text;

 

  if(valueChanged || targetValueChanged)

  {

    if(valueChanged)

    {

      this.Value = value;

    }

 

    this.TargetValue.Update(this.Value, targetValue);

 

    this.IsMatch = this.TargetValue.Matches(this.Value);

  }

}

We determine if either the value or target has changed and, if so, recalculate the target value and the match result. EnumTargetValue performs the core match logic.

Target Values

Using commas, a target value can actually be composed of multiple enumeration values. We represent this in the EnumTargetValue class by exposing a read-only wrapper of a list of parsed values:

private readonly List<object> _parsedValues = new List<object>();

 

public EnumTargetValue()

{

  this.ParsedValues = _parsedValues.AsReadOnly();

}

 

public ReadOnlyCollection<object> ParsedValues { get; private set; }

 

public string Text { get; private set; }

This list is the cache for the enumeration values we parse from the target value string. It is typed as object because we don’t have compile-time knowledge of the type of the bound enumeration – we wait to see the type of the value bound to the EnumVisibility.Value property and use that type to do the parsing.

(Later in this series, we will see why we make the parsed values publicly available.)

We also expose the source text, so we can check to see if it has changed in the beginning of the EnumCheck.Update method above. That method also calls the Update method on EnumTargetValue, which caches the text and repopulates the _parsedValues list:

public void Update(object value, string text)

{

  this.Text = text;

 

  ParseValues(value);

}

In order to parse the text, we need the enumeration value against which it will be compared, which we use to determine the type to pass to the Enum.Parse method. By inferring the enumeration type like this, we avoid requiring developers to specify another attached property alongside Value and TargetValue.

The ParseValues method parses each token in a comma-separated string into an enumeration value of the same type as the bound value:

private void ParseValues(object value)

{

  _parsedValues.Clear();

 

  if(value != null && value is Enum && !String.IsNullOrEmpty(this.Text))

  {

    var parsedValues =

      from targetValue in this.Text.Split(‘,’)

      let trimmedTargetValue = targetValue.Trim()

      where trimmedTargetValue.Length > 0

      select Enum.Parse(value.GetType(), trimmedTargetValue, false);

 

    _parsedValues.AddRange(parsedValues);

  }

}

First, we ensure the bound value is an enumeration and there is target value text to parse. Then, we tokenize the string by commas and perform a query over the resulting token. For each, we trim it, ensure it isn’t empty, and parse it to the enumeration type using a case-sensitive comparison. This gives us a sequence of enumeration values which we then add to the _parsedValues list.

Now that we have the set of parsed values, we have to compare it to the bound value. The EnumCheck.Update method above sets the EnumCheck.IsMatch property by calling the EnumTargetValue.Matches method:

public bool Matches(object value)

{

  return value == null || value.Equals("")

    ? String.IsNullOrEmpty(this.Text)

    : _parsedValues.Contains(value);

}

A null or empty bound value matches a null or empty target value, neatly supporting nullable enumerations without actually having to know the enumeration type. If a value is provided, we determine if it exists in the set of parsed values. The Contains call will ultimately use the GetHashCode and Equals methods on the bound value and each parsed value, shouldering the bulk of the equality-checking work.

Sample Project

This WPF application shows EnumVisibility in action:

Attached Behaviors Part 4 EnumVisibility.zip

It allows you to set the value of the EnumVisibility.Value attached property on three different text blocks. The first shows when Value matches TargetValue. The second shows when Value matches a comma-separated TargetValue. The third uses the WhenMatched and WhenNotMatched attached properties to show when Value does not match TargetValue instead.

Summary

Enumeration matching is useful in many scenarios. The incarnation here, which manages the Visibility property, lays the foundation for enumeration-based behaviors.

Next time, we will use the EnumCheck class to manage the IsEnabled property.

Attached Behaviors Part 3: NullVisibility

February 12th, 2011 No comments

Now that we have established a framework for writing attached behaviors, we can create any number of interesting utilities. In this post we will cover binding of the Visibility property to null and non-null values.

Scenario

A useful technique is to hide a piece of UI when its DataContext is null. This is valuable when a piece of data is optional or only shown after having been lazy-loaded. In an MVVM context, UI can be conditionally shown based on the presence of a view model. The relationship between nullity and visibility is rather meaningful and provides many everyday binding opportunities.

We will encapsulate this concept in a behavior, NullVisibility. Similar to BooleanVisibility from part 1 and part 2, it will manage the translation of a nullable value into a Visibility value using attached properties:

<TextBlock

  Text="An order is selected"

  local:NullVisibility.Value="{Binding SelectedOrder}"

/>

We can invert the translation using the WhenNull and WhenNotNull properties:

<TextBlock

  Text="No order is selected"

  local:NullVisibility.Value="{Binding SelectedOrder}"

  local:NullVisibility.WhenNull="Visible"

  local:NullVisibility.WhenNotNull="Collapsed"

/>

NullVisibility

We define the attached behavior as a static class:

public static class NullVisibility

Next, we register the attached properties which govern the behavior. First is the Value property, which we give a default value of true to match the UIElement.Visibility property’s default value of Visible. We also create static accessors to facilitate XAML usage:

public static readonly DependencyProperty ValueProperty =

  DependencyProperty.RegisterAttached(

    "Value",

    typeof(object),

    typeof(NullVisibility),

    new PropertyMetadata(true, OnArgumentsChanged));

 

public static object GetValue(UIElement uiElement)

{

  return uiElement.GetValue(ValueProperty);

}

 

public static void SetValue(UIElement uiElement, object value)

{

  uiElement.SetValue(ValueProperty, value);

}

Next, we register the WhenNull property, giving it a default value of Collapsed as the opposite of Value‘s default:

public static readonly DependencyProperty WhenNullProperty =

  DependencyProperty.RegisterAttached(

    "WhenNull",

    typeof(Visibility),

    typeof(NullVisibility),

    new PropertyMetadata(Visibility.Collapsed, OnArgumentsChanged));

 

public static Visibility GetWhenNull(UIElement uiElement)

{

  return (Visibility) uiElement.GetValue(WhenNullProperty);

}

 

public static void SetWhenNull(UIElement uiElement, Visibility visibility)

{

  uiElement.SetValue(WhenNullProperty, visibility);

}

Finally, we register the WhenNotNull property, giving it a default value of Visible to match Value‘s default:

public static readonly DependencyProperty WhenNotNullProperty =

  DependencyProperty.RegisterAttached(

    "WhenNotNull",

    typeof(Visibility),

    typeof(NullVisibility),

    new PropertyMetadata(Visibility.Visible, OnArgumentsChanged));

 

public static Visibility GetWhenNotNull(UIElement uiElement)

{

  return (Visibility) uiElement.GetValue(WhenNotNullProperty);

}

 

public static void SetWhenNotNull(UIElement uiElement, Visibility visibility)

{

  uiElement.SetValue(WhenNotNullProperty, visibility);

}

Behavior

Just like with BooleanVisibility, we declare the behavior, telling it how to create instances for individual host objects:

private static readonly AttachedBehavior Behavior =

  AttachedBehavior.Register(host => new NullVisibilityBehavior(host));

Now, we update it whenever any of the above dependency properties changes:

private static void OnArgumentsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

  Behavior.Update(d);

}

All that plumbing is about managing behavior instances. The real work is done in the IBehavior implementation, which is straightforward for NullVisibility:

private sealed class NullVisibilityBehavior : Behavior<UIElement>

{

  internal NullVisibilityBehavior(DependencyObject host) : base(host)

  {}

 

  protected override void Update(UIElement host)

  {

    host.Visibility = GetValue(host) == null

      ? GetWhenNull(host)

      : GetWhenNotNull(host);

  }

}

Sample Project

This WPF application shows NullVisibility in action:

Attached Behaviors Part 3 NullVisibility.zip

It allows you to set the value of the BooleanVisibility.Value attached property on two different text blocks. The first shows when Value is not null. The second uses the WhenNull and WhenNotNull attached properties to show when Value is null instead.

Summary

There is not a lot of code behind NullVisibility. It isn’t exactly terse (a tax for working with attached properties), but none of the pieces is complex or onerous. Writing attached behaviors does not have to be a chore.

Next time, we will explore some of these ideas using enumerations instead of Boolean values.

Attached Behaviors Part 2: Framework

February 6th, 2011 No comments

Last time, we devised a simpler syntax for defining attached behaviors in WPF and Silverlight. The new system approaches the concept at a higher level, encapsulating many of the rote mechanics common to the various implementations found on the web. It aims to make attached behaviors an everyday option, using an approach similar to many core WPF systems.

Now, we will flesh out the framework behind the API, which models three distinct aspects of attached behaviors:

  • Existence: Declare an object representing the attached behavior
  • Lifecycle: Attach and detach behavior instances to/from host objects
  • Logic: Update host objects based on changes in bound values

See the end of this post for a solution containing the framework and a usage sample.

    Existence

    Attached behaviors, similar to dependency properties, are represented by static fields:

private static readonly AttachedBehavior Behavior =

  AttachedBehavior.Register(host => new BooleanVisibilityBehavior(host));

The registration of the behavior of the BooleanVisibility class from part 1

The Register method creates an instance of AttachedBehavior, which encapsulates the ability to attach the behavior to host objects. The lambda expression indicates how to create instances of the behavior when required.

Here is the implementation:

public static AttachedBehavior Register(Func<DependencyObject, IBehavior> behaviorFactory)

{

  return new AttachedBehavior(RegisterProperty(), behaviorFactory);

}

Each attached behavior needs its own dependency property to store the IBehavior instance on each host. Rather than require behavior writes to register properties, we (carefully) create them programmatically:

private static DependencyProperty RegisterProperty()

{

  return DependencyProperty.RegisterAttached(

    GetPropertyName(),

    typeof(IBehavior),

    typeof(AttachedBehavior));

}

 

private static string GetPropertyName()

{

  return "_" + Guid.NewGuid().ToString("N");

}

First, we generate a unique name for the property by using the alphanumeric representation of a GUID (specified by the “N” format string). We prefix the property name with an underscore to ensure a legal identifier.

Then, we register an attached property with the unique name, indicating that its type is IBehavior and that AttachedBehavior owns it. Having all properties owned by the same type hides the use of attached properties completely from behavior authors.

Here is the constructor we called from the Register method:

private readonly DependencyProperty _property;

private readonly Func<DependencyObject, IBehavior> _behaviorFactory;

 

internal AttachedBehavior(DependencyProperty property, Func<DependencyObject, IBehavior> behaviorFactory)

{

  _property = property;

  _behaviorFactory = behaviorFactory;

}

    Lifecycle

The Behavior field encapsulates the lifecycle of the attached behavior. It has one method, Update, which recalculates a host object’s behavior in response to changes:

private static void OnArgumentsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

  Behavior.Update(d);

}

The handler for dependency property changes in the BooleanVisibility class of part 1

Update manages the association between the host object and an instance of the behavior. This involves three operations:

  • Attach – Create a behavior instance and associate it with the host object
  • Update –  Synchronize the behavior with the current state of the host object
  • Detach – Remove the association when the behavior no longer applies to the host object
    In concrete terms, attach and detach refer to setting and clearing the value of the dependency property we generated in the Register call. This discreetly stores the behavior instance directly within the host.

Update is straightforward to implement:

public void Update(DependencyObject host)

{

  var behavior = (IBehavior) host.GetValue(_property);

 

  if(behavior == null)

  {

    TryCreateBehavior(host);

  }

  else

  {

    UpdateBehavior(host, behavior);

  }

}

 

private void TryCreateBehavior(DependencyObject host)

{

  var behavior = _behaviorFactory(host);

 

  if(behavior.IsApplicable())

  {

    behavior.Attach();

 

    host.SetValue(_property, behavior);

 

    behavior.Update();

  }

}

 

private void UpdateBehavior(DependencyObject host, IBehavior behavior)

{

  if(behavior.IsApplicable())

  {

    behavior.Update();

  }

  else

  {

    host.ClearValue(_property);

 

    behavior.Detach();

  }

}

Before attaching or updating the behavior, we call IsApplicable to ensure it is relevant. This is the time to check things like whether dependency properties have values or whether a control is visible. For example, we may not want to attach a behavior to a combo box if it has no items.

Implementers of IBehavior supply the core logic for each of the operations:

public interface IBehavior

{

  bool IsApplicable();

 

  void Attach();

 

  void Update();

 

  void Detach();

}

A behavior is assumed to have access to the host object, as shown in the Register call where we pass the host to the constructor of BooleanVisibilityBehavior.

Logic

To minimize friction, we should allow behavior authors to work with a strongly-typed host object. We can enable this by allowing them to specify the host type as a type parameter and maintaining the untyped weak reference ourselves:

public abstract class Behavior<THost> : IBehavior where THost : DependencyObject

{

  private readonly WeakReference _hostReference;

 

  protected Behavior(DependencyObject host)

  {

    if(!(host is THost))

    {

      throw new ArgumentException("Host is not the expected type", "host");

    }

 

    _hostReference = new WeakReference(host);

  }

 

  private THost GetHost()

  {

    return (THost) _hostReference.Target;

  }

}

The GetHost method is the bridge between the weak reference and the typed API. We keep it private because derived classes won’t need it; instead, we pass them the host as a parameter in the method for each operation:

protected virtual bool IsApplicable(THost host)

{

  return true;

}

 

protected virtual void Attach(THost host)

{}

 

protected virtual void Detach(THost host)

{}

 

protected abstract void Update(THost host);

This is the core API for authoring a new behavior. Only the Update method is abstract; a behavior might not define specific logic for applicability or attaching/detaching, but it exists to respond to changes in the host.

AttachedBehavior calls them from the IBehavior methods, which ensure the host hasn’t been garbage-collected:

public bool IsApplicable()

{

  var host = GetHost();

 

  return host != null && IsApplicable(host);

}

 

public void Attach()

{

  var host = GetHost();

 

  if(host != null)

  {

    Attach(host);

  }

}

 

public void Detach()

{

  var host = GetHost();

 

  if(host != null)

  {

    Detach(host);

  }

}

 

public void Update()

{

  var host = GetHost();

 

  if(host != null)

  {

    Update(host);

  }

}

Revisiting BooleanVisibilityBehavior

The AttachedBehavior and Behavior<> types implement most of the mechanics of an attached behavior. They factor away the nitty gritty and leave behavior authors with a straightforward implementation:

private sealed class BooleanVisibilityBehavior : Behavior<UIElement>

{

  internal BooleanVisibilityBehavior(DependencyObject host) : base(host)

  {}

 

  protected override void Update(UIElement host)

  {

    host.Visibility = GetValue(host) ? GetWhenTrue(host) : GetWhenFalse(host);

  }

}

We declare the host type in the generic parameter to Behavior<>. We accept the host instance in the constructor and simply pass it through to the base class. When it comes time to update the host, it is cast to the generic type and passed to the Update method. We use the accessors for the Value, WhenTrue, and WhenFalse attached properties to determine the host’s new visibility.

(In part 1 of this series, we also listened to changes in the Visibility property and updated the Value property to match. This turned out to be more complex than expected, and so I have left that out of this iteration of the framework. The Attach/Detach methods, normally used to manage event handlers, weren’t necessary in this example.

In the majority of cases, these behaviors will manipulate a control property based on attached properties; two-way binding, a valuable but less applicable scenario, will be covered in a future post.)

Sample Project

This WPF application shows the framework in action:

Attached Behaviors Part 2 Framework.zip

It contains all of the code above and allows you to set the value of the BooleanVisibility.Value attached property on two different text blocks. The first shows when Value is true. The second uses the WhenTrue and WhenFalse attached properties to show when Value is false instead.

Summary

Different attached behaviors have very little that is unique about them. Behavior<> brings these elements to the forefront and, along with AttachedBehavior, takes care of the bookkeeping.

This core system lowers the barrier to entry for new attached behaviors, opening the door for many other ideas. Future posts in this series will cover:

  • Binding Visibility to null/not null
  • Binding Visibility to an enumeration
  • Binding IsEnabled to an enumeration
  • Binding radio buttons to an enumeration
  • Binding combo boxes and list boxes to an enumeration
Stay tuned!

Attached Behaviors Part 1: BooleanVisibility

November 11th, 2010 No comments

The DependencyObject system is at the core of the WPF and Silverlight architectures. It enables many killer features of UI development, including data binding, animation, and an overall declarative style. It is the fruit of years spent developing UI frameworks, addressing the entire idea on a more fundamental level.

One of the more interesting features is attached properties, which allow external entities to store pieces of data within dependency objects. A grid stores an object’s row and column, a canvas stores an object’s coordinates, and a docking container stores dock position. The objects remain blissfully unaware of the orthogonal features.

A particularly useful form of these properties is the attached behavior, an attached property which adds functionality to the object on which it is set. This is similar in effect to extension methods: behaviors can implement anything which uses an object’s public API. They can respond to events, such as TextChanged and Checked/Unchecked, as well as use additional attached properties to refine functionality.

Attached behaviors have been used to implement the command pattern, default buttons, and TreeView selection scrolling, as well as numerous other examples. ASP.NET even has an immensely useful implementation. The flexibility is in the simplicity: a dependency object stores a sub-object which extends it with extra behavior. This subtle form of the Mixin pattern is applicable to many problems often solved by other means.

An Example

A design consequence well-known to WPF and Silverlight developers is the Boolean/Visibility incompatibility. Visibility is an enumeration, which cannot be directly bound to Boolean properties. Instead, the colloquial approach is to define a value converter which translates as necessary:

public sealed class BooleanVisibilityConverter : IValueConverter

{

  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

  {

    return (bool) value ? Visibility.Visible : Visibility.Collapsed;

  }

 

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

  {

    return ((Visibility) value) == Visibility.Visible;

  }

}

An instance is generally included in an application’s resources:

<Application.Resources>

  <ResourceDictionary>

    <local:BooleanVisibilityConverter x:Key="booleanVisibilityConverter" />

  </ResourceDictionary>

</Application.Resources>

Then, it is used in various bindings:

<TextBlock

  Text="An error occurred."

  Visibility="{Binding HasError, Converter={StaticResource booleanVisibilityConverter}}"

/>

This is an adequate but heavy way to express the relationship between Visibility and HasError. Imagine that we instead set an attached property dedicated to the conversion:

<TextBlock

  Text="An error occurred."

  local:BooleanVisibility.Value="{Binding HasError}"

/>

This is a much clearer statement of intent, with no associated application resource. Clean.

Another aspect of the incompatibility is inverting Boolean values. I have used three approaches in the past:

  1. Add ConverterParameter=’Not’ to the binding
  2. Create a BooleanNotVisibilityConverter
  3. Add WhenTrue and WhenFalse properties to BooleanVisibilityConverter and create multiple resources
    Each of these also feels heavy. The approach with attached properties has less friction:

<TextBlock

  Text="An error occurred."

  local:BooleanVisibility.Value="{Binding HasError}"

  local:BooleanVisibility.WhenTrue="Collapsed"

  local:BooleanVisibility.WhenFalse="Visible"

/>

This neatly addresses WPF’s three-state Visibility enumeration by forcing a choice between Collapsed and Hidden. The Silverlight version works the same way, sans the Hidden option.

BooleanVisibility

Since the API is defined solely in terms of attached properties, we define it as a static class (a nice encapsulation of the feature):

public static class BooleanVisibility

First, we register the Value property, giving it a default value of true to match the UIElement.Visibility property’s default value of Visible. We also create static accessors to facilitate XAML usage:

public static readonly DependencyProperty ValueProperty =

  DependencyProperty.RegisterAttached(

    "Value",

    typeof(bool),

    typeof(BooleanVisibility),

    new PropertyMetadata(true, OnArgumentChanged));

 

public static bool GetValue(UIElement uiElement)

{

  return (bool) uiElement.GetValue(ValueProperty);

}

 

public static void SetValue(UIElement uiElement, bool value)

{

  uiElement.SetValue(ValueProperty, value);

}

Next, we register the WhenTrue property, giving it a default value of Visible to match Value‘s default:

public static readonly DependencyProperty WhenTrueProperty =

  DependencyProperty.RegisterAttached(

    "WhenTrue",

    typeof(Visibility),

    typeof(BooleanVisibility),

    new PropertyMetadata(Visibility.Visible, OnArgumentChanged));

 

public static Visibility GetWhenTrue(UIElement uiElement)

{

  return (Visibility) uiElement.GetValue(WhenTrueProperty);

}

 

public static void SetWhenTrue(UIElement uiElement, Visibility visibility)

{

  uiElement.SetValue(WhenTrueProperty, visibility);

}

Finally, we register the WhenFalse property, giving it a default value of Collapsed as the opposite of Value‘s default:

public static readonly DependencyProperty WhenFalseProperty =

  DependencyProperty.RegisterAttached(

    "WhenFalse",

    typeof(Visibility),

    typeof(BooleanVisibility),

    new PropertyMetadata(Visibility.Collapsed, OnArgumentChanged));

 

public static Visibility GetWhenFalse(UIElement uiElement)

{

  return (Visibility) uiElement.GetValue(WhenFalseProperty);

}

 

public static void SetWhenFalse(UIElement uiElement, Visibility visibility)

{

  uiElement.SetValue(WhenFalseProperty, visibility);

}

Attaching the Behavior

We create one additional attached property to hold the behavior associated with each object:

private static readonly DependencyProperty BehaviorProperty =

  DependencyProperty.RegisterAttached(

    "Behavior",

    typeof(BooleanVisibilityBehavior),

    typeof(BooleanVisibility));

The fact that we use a dependency property to associate behavior with objects is an implementation detail, so we can make it private and omit the get/set methods. BooleanVisibilityBehavior, discussed later, is the class which implements the specification.

To attach the behavior, we simply set this property. A change in Value, WhenTrue, or WhenFalse is the cue to attach it if necessary and update its state. Each property registers the OnArgumentChanged method to be called when its value changes:

private static void OnArgumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

  var uiElement = d as UIElement;

 

  if(uiElement != null)

  {

    var behavior = uiElement.GetValue(BehaviorProperty) as BooleanVisibilityBehavior;

 

    if(behavior == null)

    {

      behavior = new BooleanVisibilityBehavior(uiElement);

 

      uiElement.SetValue(BehaviorProperty, behavior);

    }

 

    behavior.Update();

  }

}

First, we ensure an instance of the behavior has been attached to the UI element through BehaviorProperty. Then, we update its state, which sets the Visibility property based on the values of Value, WhenTrue, and WhenFalse.

BooleanVisibilityBehavior

The behavior implements roughly the same functionality as BooleanVisibilityConverter:

  1. Update the UI element’s Visibility property when Value, WhenTrue, or WhenFalse changes
  2. Update Value when the UI element’s Visibility property changes

A key difference is that the behavior must listen for changes in the Visibility property, while the converter is not responsible for coordination of any kind.

The behavior class is an implementation detail as well, so we can also make it private. This is convenient because the Get/Set methods for Value, WhenTrue, and WhenFalse are in scope:

private sealed class BooleanVisibilityBehavior

{

  private readonly WeakReference _uiElementReference;

 

  internal BooleanVisibilityBehavior(UIElement uiElement)

  {

    _uiElementReference = new WeakReference(uiElement);

 

    var visibilityDescriptor = DependencyPropertyDescriptor.FromProperty(

      UIElement.VisibilityProperty,

      uiElement.GetType());

 

    visibilityDescriptor.AddValueChanged(uiElement, OnVisibilityChanged);

  }

 

  internal void Update()

  {

    var uiElement = (UIElement) _uiElementReference.Target;

 

    if(uiElement != null)

    {

      uiElement.Visibility = GetValue(uiElement)

        ? GetWhenTrue(uiElement)

        : GetWhenFalse(uiElement);

    }

  }

 

  private void OnVisibilityChanged(object sender, EventArgs e)

  {

    var uiElement = (UIElement) _uiElementReference.Target;

 

    if(uiElement != null)

    {

      var value = uiElement.Visibility == GetWhenTrue(uiElement);

 

      SetValue(uiElement, value);

    }

  }

}

We store the UI element in a WeakReference, which ensures we don’t accidentally keep it alive after it goes out of scope. Then, we use the dependency property system to add a handler for changes in the object’s Visibility property.

The Update method, which we call from the OnArgumentsChanged handler, sets the Visibility property based on the values of the argument properties. We must first ensure the UI element has not been garbage-collected.

The OnVisibilityChanged handler is the other binding direction, setting the Value property based on the value of the Visibility property.

Generalizing Attached Behaviors

The above approach is solid, but wordy. There are a lot of aspects to consider and details to get right. Writing a new attached behavior is a high-friction undertaking which can be intimidating enough to deter developers even when the effort is warranted. This concept is screaming for a framework.

Following is a proposed syntax for defining attached behaviors. It encapsulates some of the stickier points, such as the attachment logic and the weak reference. Part 2 of this series will contain the framework implementation.

First, instead of registering an attached property to hold the behavior, we raise the level of abstraction and register an attached behavior:

private static readonly AttachedBehavior Behavior =

  AttachedBehavior.Register(host => new BooleanVisibilityBehavior(host));

We tell the AttachedBehavior class how to create instances of the behavior for objects which will host it. Next, we update the host’s behavior when any of its arguments changes:

private static void OnArgumentsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

{

  Behavior.Update(d);

}

Finally, we define the behavior:

private sealed class BooleanVisibilityBehavior : Behavior<UIElement>

{

  internal BooleanVisibilityBehavior(DependencyObject host) : base(host)

  {

    var visibilityDescriptor = DependencyPropertyDescriptor.FromProperty(

      UIElement.VisibilityProperty,

      host.GetType());

 

    visibilityDescriptor.AddValueChanged(host, OnVisibilityChanged);

  }

 

  protected override void Update(UIElement host)

  {

    host.Visibility = GetValue(host) ? GetWhenTrue(host) : GetWhenFalse(host);

  }

 

  private void OnVisibilityChanged(object sender, EventArgs e)

  {

    TryUpdate(host =>

    {

      var value = host.Visibility == GetWhenTrue(host);

 

      SetValue(host, value);

    });

  }

}

We tell the base class the expected type of the host and pass the instance through to its constructor; it is responsible for the weak reference. We override Update and perform the logic without worrying about any null-checking, as the base class will ensure the host has not been garbage-collected.

OnVisibilityChanged, though, also needs access to the host. To do so, we use the TryUpdate method, giving it a lambda expression which it will only execute if the host has not been garbage-collected.

That’s it! This is much more straightforward and declarative than the raw approach. The majority of the code is concerned with the behavior itself and not with managing the instance. This style is more accessible in our everyday work, where attached behaviors may simply replace some converters.

Summary

Attached behaviors are a powerful tool in the toolkit of any WPF or Silverlight developer. They neatly encapsulate the relationship between an object and the values which drive its behavior. Their implementation complexity, though, is a large deterrent to their widespread adoption. By simplifying or removing many of the details, this framework lowers the barrier to entry and clears the path for attached behaviors to become a more common technique.

Next time, we will see how to implement the AttachedBehavior and Behavior<> classes.

Functional Caching Part 4: Dependency Injection

October 7th, 2010 2 comments

    Last time, we explored how to work caching functions into an application. We deconstructed the solution, then composed its elements in various ways to tweak behavior.

    We also identified a pattern: assembling an object graph. The process, known as Dependency Injection, is very mechanical; it requires creating and managing an ever-increasing number of objects, each of which can be arbitrarily complex. That manual labor is a significant obstacle to writing in the Dependency Injection style.

    This issue has spawned several frameworks, known as Inversion of Control containers. These systems separate the need for another object from the details of how to get it.

    This is exactly what we did before: OrderDiscountService needs an instance of IOrderRepository, and doesn’t know or care that we used CachedOrderRepository to fulfill the contract. Accordingly, this technique fits neatly into a container.

    Containers

    A container creates and manages the object instances used in an application. It is an ecosystem, where each object is an inhabitant that has its own unique relationships with other objects. Object relationships are described as B-depends-on-A, where B is an object that calls upon object A to do some work.

    Since B needs an instance of A, it has a choice:

    1. Create A directly
    2. Retrieve A from a static property or method
    3. Accept A through a constructor argument
    4. Accept A through a settable property

    3 and 4 externalize the dependency; B’s creator determines the instance of A. This makes B simpler than 1 or 2, as it doesn’t have to know how to call an external accessor. B is also more cohesive because it has less infrastructure code and is more focused on its core responsibility.

    The main purpose of a container is to understand the contours of these relationships and use that knowledge to create fully-functional objects. This frees up developers to concentrate on the project-specific tasks in the classes, instead of all the connective tissue between them.

    Autofac

    My container of choice is Autofac. It is clean and cohesive, with an excellent API*. The basic flow of Dependency Injection with Autofac is:

    1. Create a container builder
    2. Register all application types with the builder
    3. Build the container
    4. Resolve a top-level object out of the container

    Here is how we would configure OrderDiscountService to use the non-caching OrderRepository:

    var builder = new ContainerBuilder();

     

    // …Register ISession because OrderRepository requires it…

     

    builder

      .RegisterType<OrderRepository>()

      .As<IOrderRepository>()

      .InstancePerDependency();

     

    builder.RegisterType<OrderDiscountService>().InstancePerDependency();

    This registers the OrderRepository type under the IOrderRepository interface, meaning any other object which has a dependency on IOrderRepository will be given an instance of OrderRepository. The InstancePerDependency instruction tells the container to create a new instance every time an object has a dependency on IOrderRepository.

    Here is how we would resolve an instance of OrderDiscountService from the container:

    var container = builder.Build();

     

    var discountService = container.Resolve<OrderDiscountService>();

     

    var orderId = 1;

     

    discountService.ApplyDiscount(orderId, 0.10);

    The builder creates a container with all of the registrations. We then resolve an instance of OrderDiscountService and use it. The container encapsulates the messy, rote details of wiring the object graph. It inspects the constructor to determine its dependencies. When it finds one on IOrderRepository, it knows to create an instance of OrderRepository because of our prior registration.

    To add caching, we simply have to change the object which is registered as IOrderRepository: 

    builder

      .Register(c =>

        new CachedOrderRepository(new OrderRepository(c.Resolve<ISession>())))

      .As<IOrderRepository>()

      .SingleInstance();

    Here, we declare that when an object depends on IOrderRepository, we create an instance of OrderRepository and wrap it in CachedOrderRepository. Other objects remain oblivious to the new capabilities.

    We use the context variable c to fulfill
    OrderRepository
    ‘s dependency on ISession. We have to spell out the dependencies because we want to run arbitrary registration code. This is what the container automagically does for us when we use the RegisterType method.

    We also change the lifetime to SingleInstance, which tells the container to use the same instance to fulfill all dependencies. This extends the benefits of caching to all objects with minimal effort.

    Summary

    This series has explored caching as implemented in Dependency Injection style. First, we defined result caching for any method with a single parameter and a return value. Next, we defined concurrent caching, allowing multiple threads to safely invoke the caching method. Then, we seamlessly weaved caching into an implementation of IOrderRepository using the Decorator pattern.

    In this final installment, we expressed the same object graph as last time, but in a declarative fashion. The boring tab-A-slot-B mechanics are the container’s specialty; by delegating that task, we gain more time to concentrate on providing business value.

    * I got the chance to meet Nick Blumhardt, Autofac’s founder, at PDC 2008. Let’s just say I trust his code.

    Refining WCF Service Proxies in Silverlight

    August 24th, 2010 No comments

    Silverlight applications face some novel architectural challenges compared to desktop or web applications. One of the most fundamental concerns, data access, is heavily affected by the constraints of running in a browser. The prevailing pattern, WCF service proxies, is solid, but has some rough edges.

    Here is a technique I use to make WCF service proxies more writable, readable, composable, testable, and maintainable. That is just my opinion, of course, so see if you agree.

    Data Access in Silverlight is Different

    Silverlight applications are executed by a plugin which runs in the browser on a client’s machine. This means they cannot directly connect to server resources, such as as databases, for security reasons. They do, however, have access to their host web site, which can act on behalf of the Silverlight applications to fetch or update data.

    To do so, Silverlight applications require points of contact on the server dedicated to carrying out those actions. These are often in the form of WCF Services, endpoints in a web site which process requests sent from Silverlight applications.

    Each of these services exposes one or more contracts, sets of operations which comprise the functionality of the endpoint. Each operation has a signature composed of its name, inputs, and outputs. The data types in the signature each has its own contract describing its structure. A service contract and the associated data contracts together make a service definition, the unit of communication between Silverlight applications and their host sites.

    Service References

    A service reference is how Silverlight code communicates with a WCF service. Visual Studio generates strongly-typed client code from services’ metadata, machine-readable descriptions of service and data contracts. The generated code is commonly referred to as a proxy for the service.

    The proxy programming model is straightforward: all types resides in a single namespace, where client classes implement the contracts of the referenced service. Operations are methods on those classes, and every custom data type in every operation is also generated.

    Calls made with proxies look like this:

    public void WriteVisitorCountAsync()

    {

      var client = new SiteInfoClient();

     

      client.GetVisitorCountCompleted += OnGetVisitorCountCompleted;

     

      client.GetVisitorCountAsync();

    }

     

    private void OnGetVisitorCountCompleted(

      object sender,

      GetVisitorCountCompletedEventArgs e)

    {

      if(e.Error != null)

      {

        Console.WriteLine(“Error: {0}”, e.Error);

      }

      else if(e.Cancelled)

      {

        Console.WriteLine(“Cancelled”);

      }

      else

      {

        Console.WriteLine(“Visitor count: {0}”, e.Result);

      }

    }

    Proxies work like this because the networking infrastructure in Silverlight is asynchronous, a necessity in a browser environment where the UI thread can’t be tied up by expensive calls. Network calls do not start and finish on the same thread of execution. Instead, we package the handler code in a delegate and attach it to the client’s event. The client calls the delegate at some future time, whenever the response is received or a timeout elapses. WriteVisitorCountAsync returns immediately after the call to GetVisitorCountAsync, without blocking the thread.

    Looking Closer

    A few elements of this pattern are less than optimal:

    • We create the client instance directly with no parameters, which assumes the proper service configuration exists. Is the point of usage the best place to make that decision?
    • The whole invocation is three statements, making calls feel heavy
    • The handler code lives in a separate method, making calls feel heavy
    • We have to check for an error or cancellation, adding branching logic to the handler and making calls feel heavy
    • We control the client’s lifetime, meaning everyone who reads the code has to work out for themselves what happens to the client object once the reference goes out of scope (it is held by the Silverlight infrastructure in order to do the callback)

    Ideally, the point of usage would have these characteristics:

    • Client creation, configuration, and lifetime management are done elsewhere
    • Declarative invocation
    • No control flow statements

    These minor touches would make calls feel more lightweight and approachable by clearing decisions from developers’ paths. We want the focus on the bricks, not the mortar.

    A New Style

    Let’s imagine the call to GetVisitorCountAsync with these traits in mind:

    public class VisitorCountWriter

    {

      private readonly IServiceProxy<SiteInfoClient> _siteInfoProxy;

     

      public VisitorCountWriter(IServiceProxy<SiteInfoClient> siteInfoProxy)

      {

        _siteInfoProxy = siteInfoProxy;

      }

     

      public void WriteVisitorCountAsync()

      {

        _siteInfoProxy.ExecuteAsync<GetVisitorCountCompletedEventArgs>(

          (client, handler) => client.GetVisitorCountCompleted += handler,

          client => client.GetVisitorCountAsync(),

          args => Console.WriteLine(“Visitor count: {0}”, args.Result),

          exception => Console.WriteLine(“Error: {0}”, exception),

          () => Console.WriteLine(“Cancelled”));

      }

    }

    What a mouthful! Let’s break it down piece by piece.

    Proxy Call – We declare we are executing a call whose completed event handler takes the specified argument type:

    _siteInfoProxy.ExecuteAsync<GetVisitorCountCompletedEventArgs>(

    Event Subscription – Given a client instance and some event handler, we subscribe the handler to the client’s completed event. _siteInfoProxy is responsible for creating the instance and the handler. We just wire it to the right event:

    (client, handler) => client.GetVisitorCountCompleted += handler

    Client Call – Given the client, we make the actual call:

    client => client.GetVisitorCountAsync()

    Success Handler – Given the completed arguments, we write Result to the screen:

    args => Console.WriteLine(“Visitor count: {0}”, args.Result)

    Error Handler – Given the exception, we write it to the screen:

    exception => Console.WriteLine(“Error: {0}”, exception)

    Cancellation Handler – Given no arguments, we write a message to the screen:

    () => Console.WriteLine(“Cancelled”)

    It’s a bit to take in at first, but becomes natural fairly quickly. The IServiceProxy<> implementation takes care of client creation, configuration, and lifetime. The handlers are specified in the logical order of the pattern, and the statement contains all the code from the original form’s three statements and separate event handler. We’ve factored the approach so we only specify the unique parts of each call.

    Code as Data

    This is the interface which enables the new style:

    public interface IServiceProxy<TClient>

    {

      void ExecuteAsync<TCompletedEventArgs>(

        Action<TClient, EventHandler<TCompletedEventArgs>> subscribeToCompletedHandler,

        Action<TClient> execute,

        Action<TCompletedEventArgs> onCompleted = null,

        Action<Exception> onError = null,

        Action onCancelled = null)

        where TCompletedEventArgs : AsyncCompletedEventArgs;

    }

    Each parameter is a delegate in the Action family, which represent methods with no return value. The type arguments of each action correspond to the parameters of the previous lambda expressions. ExecuteAsync<> parameterizes portions of the algorithm by allowing custom code to be packaged into arguments (see the Template Method pattern).

    The first two parameters define the code which initiates the call; the last three define the handling of the response. The success, error, and cancelled handlers are all optional because each has a reasonable default:

      Default behavior if null
    onCompleted No action (equivalent to a one-way call)
    onError throw exception from event arguments
    onCancelled throw exception

    Finally, we constrain TCompletedEventArgs to derive from AsyncCompletedEventArgs, the base type for event argument types in generated proxies. It defines the Cancelled and Error properties, allowing us to process all responses in the same way.

    The Method Behind the Madness

    This is a reasonable implementation of IServiceProxy<>:

    public sealed class ServiceProxy<TClient> : IServiceProxy<TClient>

    {

      private readonly Func<TClient> _clientFactory;

     

      public ServiceProxy(Func<TClient> clientFactory)

      {

        _clientFactory = clientFactory;

      }

     

      public void ExecuteAsync<TCompletedEventArgs>(

        Action<TClient, EventHandler<TCompletedEventArgs>> subscribeToCompletedHandler,

        Action<TClient> execute,

        Action<TCompletedEventArgs> onCompleted = null,

        Action<Exception> onError = null,

        Action onCancelled = null)

        where TCompletedEventArgs : AsyncCompletedEventArgs

      {

        var client = _clientFactory();

     

        subscribeToCompletedHandler(

          client,

          (sender, args) =>

          {

            if(args.Error != null)

            {

              if(onError != null)

              {

                onError(args.Error);

              }

              else

              {

                throw args.Error;

              }

            }

            else if(args.Cancelled)

            {

              if(onCancelled != null)

              {

                onCancelled();

              }

              else

              {

                throw new OperationCanceledException();

              }

            }

            else

            {

              if(onCompleted != null)

              {

                onCompleted(args);

              }

            }

          });

     

        execute(client);

      }

    }

    The constructor accepts a method which creates client instances, which serves our goal of creating and configuring clients elsewhere. Different factories can be used to control client lifetimes. For example, a factory may return the same instance for every call, or use some heuristic to pool instances.

    First, we get a client instance. Then, we invoke subscribedToCompletedHandler, passing in the client and a lambda expression for the handler. In the handler, we check for the error and cancelled states and take the appropriate actions. Otherwise, if there is a success handler, we invoke it.

    Now that the handler is subscribed, we invoke execute, passing in the client, and that’s it! ExecuteAsync<> looks very similar to the original code; it puts these details in a single place, allowing us to work at a level of abstraction above them.

    Using ServiceProxy<>

    This is how we would put ServiceProxy<> in action:

    var proxy = new ServiceProxy<SiteInfoClient>(() => new SiteInfoClient());

     

    var writer = new VisitorCountWriter(proxy);

     

    writer.WriteVisitorCountAsync();

    We state that when creating clients, we create an instance per call using the default c onstructor. This will use the configuration found in the ServiceReferences.ClientConfig file generated with the proxy. However, we could easily configure the client any other way, such as with alternate endpoints or bindings.

    However, the constructor call has a lot of ceremony. We shouldn’t need to specify the client type twice. To make this a little nicer, we can have the compiler infer the client type from the return type of the lambda expression:

    var proxy = ServiceProxy.WithFactory(() => new SiteInfoClient());

    The WithFactory method simply reads TClient from the parameter:

    public static class ServiceProxy

    {

      public static IServiceProxy<TClient> WithFactory<TClient>(

        Func<TClient> clientFactory)

      {

        return new ServiceProxy<TClient>(clientFactory);

      }

    }

    Summary

    We identified friction points in the standard approach to using generated proxies and created a solution which encapsulates many of the pattern’s details. The resulting API requires less decisions and rote code at the point of usage. It also externalizes client configuration and lifetime from the core concern of making service calls, increasing the cohesion of the solution while creating extension points which allow for its graceful evolution.

    A win all around.

    Tags: , , ,

    Functional Caching Part 3: Decoration

    August 2nd, 2010 No comments

      Now that we have established the cached function pattern and adapted it to add concurrency support, it’s time to put the functions in action.

      First, let’s create a home for our GetOrder method:

      public interface IOrderRepository

      {

        Order GetOrder(int id);

      }

      This interface represents a repository (data store) which contains orders, like a database, web service, or XML file. It abstracts away persistence details such as connection strings, URLs, file paths, and query mechanisms. Using an interface communicates to the reader that GetOrder is not defined in terms of any concrete details.

      The only decision we’ve made so far is the signature of GetOrder; we haven’t had to consider class vs. struct, making the class abstract, sealing it, or making GetOrder virtual. We also haven’t locked implementers into a single inheritance hierarchy. By delaying these minor decisions, interfaces keep the focus on what needs to be done, not how it’s done.

      Before we implement IOrderRepository, let’s see how it would be used:

      public class OrderDiscountService

      {

        private readonly IOrderRepository _orders;

       

        public OrderDiscountService(IOrderRepository orders)

        {

          _orders = orders;

        }

       

        public void ApplyDiscount(int orderId, double percentage)

        {

          var order = _orders.GetOrder(orderId);

       

          order.ApplyDiscount(percentage);

        }

      }

      OrderDiscountService declares its dependency on IOrderRepository by accepting it in the constructor. This separates the conceptual dependency on the GetOrder operation from any details of its execution. The actual IOrderRepository implementation is left up to configuration, a concern for some other class.

      There is a subtle beauty in this. Classes define their boundaries through their dependencies. When those boundaries are interfaces, which have no inherent implementation, a class stands on its own: it can be fully understood without the mental weight of those external details.

      An outstanding benefit of this style is that most classes start to look and feel the same: declare constructor dependencies and implement an interface using private methods. It normalizes complexity with a format that can handle problems large and small. This consistency also pays dividends over time by making it less painful to ease back into past codebases.

      The Core Implementation

      We can write GetOrder by querying an NHibernate session:

      public sealed class OrderRepository : IOrderRepository

      {

        private readonly ISession _session;

       

        public OrderRepository(ISession session)

        {

          _session = session;

        }

       

        public Order GetOrder(int id)

        {

          return _session.Linq<Order>().Where(order => order.Id == id).SingleOrDefault();

        }

      }

      An NHibernate session represents a single conversation with a database. We don’t want to know the gory details of creating one of those suckers, so we declare a dependency on it instead. This communicates to the reader that this class participates in an existing conversation.

      The query is fairly straightforward. We select the one order whose ID matches the parameter, or null if that ID doesn’t exist. This class is really only interesting because it is the NHibernate version of it; we can imagine similar Entity Framework or LINQ to SQL implementations.

      Wrappers with Mad Cache

      OrderRepository is very cohesive: its only concern is to query. Adding more functionality to it, such as caching, would muddle the class’s core intent. In situations such as this, we can use the Decorator pattern to wrap the class with new functionality.

      Decoration here means implementing IOrderRepository again and also accepting it in the constructor. The outer GetOrder is written in terms of the inner one, altering it by using a cached version of the function:

      public sealed class CachedOrderRepository : IOrderRepository

      {

        private readonly Func<int, Order> _getOrder;

       

        public CachedOrderRepository(IOrderRepository innerRepository)

        {

          _getOrder = innerRepository.GetOrder;

       

          _getOrder = _getOrder.Cached();

        }

       

        public Order GetOrder(int id)

        {

          return _getOrder(id);

        }

      }

      We declare that GetOrder passes the call through to the _getOrder member. To initialize the function, first we assign it to the inner, uncached implementation:

      _getOrder = innerRepository.GetOrder;

      This means exactly the same as:

      _getOrder = new Func<int, Order>(innerRepository.GetOrder);

      The C# compiler is smart enough to see that _getOrder is of type Func<int, Order>, a delegate type, and allows us to assign the method directly, rather than have us type out something it can infer. Neat.

      Next, we get a cached version of the function we just assigned:

      _getOrder = _getOrder.Cached();

      Voila! CachedOrderRepository connects caching to GetOrder – it doesn’t actually implement either of them. All three concepts are neatly separated, and each has a very small surface area for external changes to affect it. Our intent is clear: cache the inner repository’s GetOrder method.

      Some Assembly Required

      Like when creating a Lego structure or writing a story, we must weave our various building blocks together in a single context. This action is called composition, the natural yang to the yin of fine-grained objects. In our case, this means creating an object graph: calling the series of constructors necessary to create an instance of OrderDiscountService:

      var session = …;

      var orders = new OrderRepository(session);

      var discountService = new OrderDiscountService(orders);

       

      discountService.ApplyDiscount(7, 0.10);

      We used the non-cached version of the repository because we are only applying a discount to a single order. There is no return on investment for caching the instance. However, if we were to apply a discount to a series of orders which may contain duplicates, we could use the cached version to avoid retrieving the same order multiple times:

      var session = …;

      var orders = new CachedOrderRepository(new OrderRepository(session));

      var discountService = new OrderDiscountService(orders);

       

      foreach(var orderId in new[] { 1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7 })

      {

        discountService.ApplyDiscount(orderId, 0.10);

      }

      The only difference is that we set orders to a cached version of the repository. OrderDiscountService has no idea that the IOrderRepository it receives is actually a graph with its own composed behaviors. The structure of the graph is a configuration detail of which none of the classes has any knowledge.

      Summary

      We defined an interface for our GetOrder example method and saw how it would be used. We discussed some benefits of interfaces and reflected on using them to create isolatable objects. We implemented IOrderRepository in a typical query-based fashion and seamlessly added caching using the Decorator pattern, keeping it separate from the core query concern.

      We also created multiple configurations of these objects to address slight differences in context. Soon, we will see how we can simply declare these relationships and hand off the manual labor to a framework.