Can I define a Binding
as a Resource
and then reuse it with different Controls
properties?
Example:
Binding:
Direct answer to your question is "yes, you can define a binding as a resource". The problem here is how do you then make any use of it? One possibility is to create an extension class which would pull the binding from the resources and apply it:
public class BindingResourceExtension : StaticResourceExtension
{
public BindingResourceExtension() : base() { }
public BindingResourceExtension(object resourceKey) : base(resourceKey) { }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = base.ProvideValue(serviceProvider) as BindingBase;
if (binding != null)
return binding.ProvideValue(serviceProvider);
else
return null; //or throw an exception
}
}
Usage example:
<Window.Resources>
<ResourceDictionary>
<Binding x:Key="MyBinding" Path="MyProperty" Mode="TwoWay" />
</ResourceDictionary>
</Window.Resources>
(...)
<TextBox Text="{ns:BindingResource MyBinding}" />
Can this solution be used in MultiBinding
?
Yes, it can:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="First: {0}, Second: {1}">
<Binding Path="SomeProperty" />
<ns:BindingResource ResourceKey="MyBinding" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
There is however one drawback to this - although everything will work in run-time, the XAML Designer will complain that BindingResourceExtension
is not of proper type to be put in the MultiBinding.Bindings
collection. But, thankfully, there is a quick solution - simply use StaticResourceExtension
instead! So this, while being functionally equivalent in run-time, will be accepted by the designer:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="First: {0}, Second: {1}">
<Binding Path="SomeProperty" />
<StaticResource ResourceKey="MyBinding" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
Here are two ways to not do exactly what you want:
1. Using a custom markup extension
Skipped all nullchecks etc. to keep it short.
using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
public class BindingDefinition
{
public PropertyPath Path { get; set; }
public BindingMode Mode { get; set; }
}
[MarkupExtensionReturnType(typeof(BindingExpression))]
public class ApplyBindingDefinition : MarkupExtension
{
public BindingDefinition Definition { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding
{
Path = this.Definition.Path,
Mode = this.Definition.Mode
};
return binding.ProvideValue(serviceProvider);
}
}
<Window.Resources>
<local:BindingDefinition x:Key="MyProperty"
Mode="TwoWay"
Path="MyProperty" />
</Window.Resources>
<TextBox>
<TextBox.Text>
<!-- using element style here as the parser chokes on parsing nested markupextensions -->
<local:ApplyBindingDefinition Definition="{StaticResource MyProperty}" />
</TextBox.Text>
</TextBox>
2. Making the PropertyPath a resource
May or may not be enough for your needs.
<Window.Resources>
<PropertyPath x:Key="MyPropertyPath">MyProperty</PropertyPath>
</Window.Resources>
...
<TextBox Text="{Binding Path={StaticResource MyPropertyPath}}" />