Binding and xaml markup extensions using localization as an example
One of the key moments in the development of xaml -oriented applications is the use of bindings ( the Bindings ). A binding is a mediator (mediator), with the help of which property values are synchronized between related objects.
It is worth noting an obvious, but important nuance: although the binding somehow refers to interacting objects, it does not deter them from garbage collection!
Inheriting from the Binding class is allowed, but for security reasons, overriding the ProvideValue method , which is associated with the main logic of work, is not allowed. This one way or another provokes developers to use the Converter pattern.which is closely intertwined with the theme of bindings.
Bindings are a very powerful tool, but in some cases their declaration is verbose and inconvenient with regular use, for example, for localization. In this article, we will analyze a simple and elegant way that makes the code much cleaner and more beautiful.

Declaring bindings in xaml is permissible in two ways:
Obviously, the first method does not look very concise, while the second, based on the use of markup extensions , is used most often. On the WPF platform, it is possible to create custom markup extensions . For example, they are conveniently used for localization.
In the simplest case, you need to inherit from the MarkupExtension class and implement the ProvideValue method , in which to obtain the desired value by key.
But such an implementation does not support hot-swapping of the language during program execution. To make this improvement is necessary, firstly, to keep a reference to the localized interface element, and secondly, that the less obvious way or another have in the application refer to himself ekemplyar class Localizing , to protect it from the garbage collector, and, thirdly, it is required to correctly implement the subscription and unsubscription from the language change event.
By doing these things incorrectly, you are guaranteed to get memory leaks if the views are created and disappear dynamically during the application, and in many cases this is the case. That is, adding a seemingly not the most complicated function, you will have to deal with non-trivial topics of weak links and weak subscriptions to events . And the code is not very simple.
Moreover, xaml -platform the Windows Phone , the Windows Store and Xamarin.Forms there is no possibility to create custom markup extension, which suggests the idea of using bindings as markup extensions ...
Let's not beat around the bush, here's what we need:
It is noteworthy that the binding is a converter for itself. As a result, we get a very similar behavior, as when inheriting from the MarkupExtension class , but, in addition, it remains possible to use standard mechanisms for controlling garbage collection!
Now the logic for localization looks nowhere simpler:
It is easy to add the ability to change the case of letters:
In xaml, a record looks convenient and beautiful, but there are some limitations of markup parsers on various platforms:
To get rid of the mandatory m: prefix on WPF, you need to put the markup extension in a separate assembly and specify the following directives in Properties / AssemblyInfo.cs :
To adjust the prefix name on a Windows Phone or Store :
Use snap extensions ( the Binding the Extensions ) on WPF does not exclude normal markup extensions, but in some cases is even more secure and simple option. Also, all this is not limited only to localization, but is suitable for many other purposes ... The
demonstrated approach is intensively used in the Aero Framework library , which was described a little earlier . It also comes with an example project where you can see all of these mechanisms in action. Thank you for attention!
It is worth noting an obvious, but important nuance: although the binding somehow refers to interacting objects, it does not deter them from garbage collection!
Inheriting from the Binding class is allowed, but for security reasons, overriding the ProvideValue method , which is associated with the main logic of work, is not allowed. This one way or another provokes developers to use the Converter pattern.which is closely intertwined with the theme of bindings.
Bindings are a very powerful tool, but in some cases their declaration is verbose and inconvenient with regular use, for example, for localization. In this article, we will analyze a simple and elegant way that makes the code much cleaner and more beautiful.

Declaring bindings in xaml is permissible in two ways:
Obviously, the first method does not look very concise, while the second, based on the use of markup extensions , is used most often. On the WPF platform, it is possible to create custom markup extensions . For example, they are conveniently used for localization.
In the simplest case, you need to inherit from the MarkupExtension class and implement the ProvideValue method , in which to obtain the desired value by key.
But such an implementation does not support hot-swapping of the language during program execution. To make this improvement is necessary, firstly, to keep a reference to the localized interface element, and secondly, that the less obvious way or another have in the application refer to himself ekemplyar class Localizing , to protect it from the garbage collector, and, thirdly, it is required to correctly implement the subscription and unsubscription from the language change event.
By doing these things incorrectly, you are guaranteed to get memory leaks if the views are created and disappear dynamically during the application, and in many cases this is the case. That is, adding a seemingly not the most complicated function, you will have to deal with non-trivial topics of weak links and weak subscriptions to events . And the code is not very simple.
Moreover, xaml -platform the Windows Phone , the Windows Store and Xamarin.Forms there is no possibility to create custom markup extension, which suggests the idea of using bindings as markup extensions ...
Let's not beat around the bush, here's what we need:
public abstract class BindingExtension : Binding, IValueConverter
{
protected BindingExtension()
{
Source = Converter = this;
}
protected BindingExtension(object source) // set Source to null for using DataContext
{
Source = source;
Converter = this;
}
protected BindingExtension(RelativeSource relativeSource)
{
RelativeSource = relativeSource;
Converter = this;
}
public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
It is noteworthy that the binding is a converter for itself. As a result, we get a very similar behavior, as when inheriting from the MarkupExtension class , but, in addition, it remains possible to use standard mechanisms for controlling garbage collection!
Now the logic for localization looks nowhere simpler:
public partial class Localizing : Base.BindingExtension
{
public static readonly Manager ActiveManager = new Manager();
public Localizing()
{
Source = ActiveManager;
Path = new PropertyPath("Source");
}
public Localizing(string key)
{
Key = key;
Source = ActiveManager;
Path = new PropertyPath("Source");
}
public string Key { get; set; }
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var key = Key;
var resourceManager = value as ResourceManager;
var localizedValue = resourceManager == null || string.IsNullOrEmpty(key)
? ":" + key + ":"
: (resourceManager.GetString(key) ?? ":" + key + ":");
return localizedValue;
}
}
public partial class Localizing
{
public class Manager : INotifyPropertyChanged
{
private ResourceManager _source;
public ResourceManager Source
{
get { return _source; }
set
{
_source = value;
PropertyChanged(this, new PropertyChangedEventArgs("Source"));
}
}
public string Get(string key, string stringFormat = null)
{
if (_source == null || string.IsNullOrWhiteSpace(key)) return key;
var localizedValue = _source.GetString(key) ?? ":" + key + ":";
return string.IsNullOrEmpty(stringFormat)
? localizedValue
: string.Format(stringFormat, localizedValue);
}
public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { };
}
}
It is easy to add the ability to change the case of letters:
public partial class Localizing : Base.BindingExtension
{
public enum Cases
{
Default,
Lower,
Upper
}
public static readonly Manager ActiveManager = new Manager();
public Localizing()
{
Source = ActiveManager;
Path = new PropertyPath("Source");
}
public Localizing(string key)
{
Key = key;
Source = ActiveManager;
Path = new PropertyPath("Source");
}
public string Key { get; set; }
public Cases Case { get; set; }
public override string ToString()
{
return Convert(ActiveManager.Source, null, Key, Thread.CurrentThread.CurrentCulture) as string ??
string.Empty;
}
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var key = Key;
var resourceManager = value as ResourceManager;
var localizedValue = resourceManager == null || string.IsNullOrEmpty(key)
? ":" + key + ":"
: (resourceManager.GetString(key) ?? ":" + key + ":");
switch (Case)
{
case Cases.Lower:
return localizedValue.ToLower();
case Cases.Upper:
return localizedValue.ToUpper();
default:
return localizedValue;
}
}
}
In xaml, a record looks convenient and beautiful, but there are some limitations of markup parsers on various platforms:
To get rid of the mandatory m: prefix on WPF, you need to put the markup extension in a separate assembly and specify the following directives in Properties / AssemblyInfo.cs :
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Aero.Markup")]
[assembly: XmlnsPrefix("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "m")]
To adjust the prefix name on a Windows Phone or Store :
[assembly: XmlnsDefinition("clr-namespace:Aero.Markup;assembly=Aero.Phone", "Aero.Markup")]
[assembly: XmlnsPrefix("clr-namespace:Aero.Markup;assembly=Aero.Phone", "m")]
Use snap extensions ( the Binding the Extensions ) on WPF does not exclude normal markup extensions, but in some cases is even more secure and simple option. Also, all this is not limited only to localization, but is suitable for many other purposes ... The
demonstrated approach is intensively used in the Aero Framework library , which was described a little earlier . It also comes with an example project where you can see all of these mechanisms in action. Thank you for attention!