Jerry Nixon on Windows: Custom UWP-XAML attached properties

Jerry Nixon on Windows

Saturday, February 3, 2018

Custom UWP-XAML attached properties

Look, this article is for me. I keep forgetting the basics of XAML attached properties & some advanced syntax. If this helps you, too, great. 
As the author of Template 10 (the best UWP framework) I keep on my UWP toes with XAML & WinRT. I may not be a XAML Jedi, but I’m on the path. You’d think after writing about this in my Navigation View article in MSDN Magazine article last month I would have it all locked in. But, I’m the type of guy who forgets things. Even stuff I mastered just last month. So, here goes.

Containing class

The only requirement for an attached property is that its containing class derive from DependecyObject. The class cannot be static.

Basic property

A simple property holds a strongly-typed value. Every attached property must have a default value set in PropertyMetadata during RegisterAttached.

Constraining to a type

An attached property is, by default, available to every Dependency Object. To limit this, change the signatures of the static Get()/Set() methods.

XAML syntax

After adding a namespace, you can use XAML’s simple and complex property syntax for attached properties. Each have type-safety.

Note: The approach to data binding to attached properties is identical to databinding dependency properties directly on the control. Either syntax is supported.

Setting in Styles

It’s also possible to use style setters. The syntax is nearly the same.

Handling change

The most reliable approach to handling changed values is in the changed handler set in PropertyMetadata. It’s already on the UI thread.

Note: You’ll need to cast both the sender and the e.NewValue (there is also an e.OldValue) to the correct types before you act on them.

Updating controls

Sometimes properties are for updating controls. The constructor has no reference to the controls. Operations must execute during the Set() method.

Setting values in code-behind

Attached properties, like dependency properties are only a property bag, not real properties. As a result, they are stored as [object], not strong-types.

Reading values in code-behind

Reading the value of attached properties is the same as reading dependency properties. And like dependency properties, you need to cast the value.

Enumerable attached properties

Sometimes a scalar value isn’t enough, you want to store an IEnumerable. Attached properties can do this natively: use List.

Important: it is up to you, the developer, to instantiate the list. In the Get() method, check if the value is null. If it is, create it, then return it.

XAML Syntax

It’s simple to add items to an attached property of IEnumerable. The XAML platform understands how to Add() for you, so there’s nothing special.

Note: the simple XAML syntax is not supported here. If you are binding to it, you skip the Get() changes and bind a List, not its items.

Handling list changes

A List does not raise events when it is changed, and the attached property changed event will never raise. You need an ObservableColelction.

That’s it.

Question & Answer

What about that literal string?

Unlike dependency properties, attached properties have no real object or member for to use nameof(). This means that literal string is required.

What do you call the control using the attached property?

According to the Microsoft Docs, that’s referred to as the “owning type”. See here:

Can I iterate through all the owning types?

If on each Set() you store a control reverence in a static List you can, but you have to wait for Set() to be called. Otherwise, no.

Can I put all my attached properties in a remote assembly?

Yep. You can put all of them or some of them. You just need to be able to create the namespace reference in your XAML declaration.

I assume the value is disposed when the owning type is disposed?

That’s what I assume. Yeah.

Are attached properties inherited like dependency properties?

Nope. That's one big difference.

What about the "Cannot add instance of type ObservableCollection"  exception?

That means you aren't constructing the list in the Set() method, dummy.

// Best of luck.