Binding as a Resource
Asked Answered
S

2

23

Can I define a Binding as a Resource and then reuse it with different Controls properties?

Example:

Binding:

<Window.Resources>        
    <Binding x:Key="MyBinding" Path="MyProperty" Mode="TwoWay" />
</Window.Resources>

Reuse in XAML:

<TextBox Text="{StaticResource MyBinding}" />

After declaring Binding as above I got the error:

"The name 'InitializeComponent' does not exist in the current context"

Is there any way to reuse the same Binding in different contexts?

Schmidt answered 28/4, 2016 at 10:40 Comment(6)
See here: https://mcmap.net/q/586153/-binding-instance-as-resource/1136211Kohl
@Kohl it's gives some methods but of no use for me. I can't conclude any significant infoSchmidt
You can apply Binding only to a DP of DO.Hardiness
@Hardiness I know that, and that is not my question.Schmidt
Technically interesting but what is the point (use case?) in reusing a binding as a resource? Isn't the property-name itself not sufficient for referencing the source property? Also you are kind of predefining the binding mode which might not be suited for the binding target at all.Pitts
@Pitts it's kind of benefit when a large no of DataTemplate has to be created for ItemsControl. And you know every template is essentially gonna bound to same properties. So if we can achieve Binding as a resource some amount of re usability can be achieved. see this #36716510Schmidt
I
19

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>
Interpretive answered 1/5, 2016 at 4:59 Comment(7)
great solution, i wanted solution exactly like this...... but I'm still not clear about how is this working? class name is BindingResourceExtension but in text property you have defined BindingResource?Schmidt
When using extension classes in XAML you can omit the "Extension" suffix - it's a feature of XAML parser. Similar principle lets you omit the "Attribute" suffix when using attribute classes. That of course is true as long as it doesn't introduce any ambiguity. Note the StaticResourceExtension class from which we derive - it's the same class that is used as {StaticResource (...)} in XAML.Interpretive
ok.. and why do we have to put this binding in resourcedictionary? if i just put the binding in Window.Resource it doesn't work, strange.Schmidt
That's because XAML parser misinterprets your intentions - it is designed to "think" that you're trying to bind the Window.Resources property using the specified binding rather than add the binding to the dictionary.Interpretive
can this be used in a multibinding? I can't figure out the syntax. (I want one of the inner bindings of the multibinding to be reused)Medallist
Got error with VS2015 A 'Binding' cannot be set on the 'Value' property of type 'DictionaryEntry'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.Strenuous
Haven't tested this, but you should be able to add [MarkupExtensionReturnType(typeof(BindingBase))] to the extension and then it will be detected by the designer as a valid type for MultiBinding.BindingDominance
C
4

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}}" />
Cheapskate answered 30/4, 2016 at 18:9 Comment(4)
I'm looking for somewhat same solution... if this is possible for whole binding...that way I want to achieve max re usability (for binding syntax) for some dynamically generated controls of different kinds....Schmidt
@Kylo Updated the answer.Cheapskate
Designer complains after second build but the designer is broken in countless ways.Cheapskate
it's a good solution, however the lines of code that I am trying to avoid is still there...It's would be much better solution if I could define the ApplyBindingDefinition in resources and then just reuse it. I hope above make sense, but thanks anyways.Schmidt

© 2022 - 2024 — McMap. All rights reserved.