Question

I am having a ValueConverter used for binding 'To' Value in a StoryBoard animation, similar to the answer - WPF animation: binding to the “To” attribute of storyboard animation.

The problem is I am repeating the below piece of code for MultiBinding ValueConverter in couple of places.

    <MultiBinding Converter="{StaticResource multiplyConverter}">
       <Binding Path="ActualHeight" ElementName="ExpanderContent"/>
       <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
    </MultiBinding>

I want to remove this duplicate code by storing the result of the ValueConverter to a resource variable so I can bind this local Variable directly to the story board.

<system:Double x:Key="CalculatedWidth">
    <MultiBinding Converter="{StaticResource multiplyConverter}">
        <Binding Path="ActualHeight" ElementName="ExpanderContent"/>
        <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
    </MultiBinding>
</system:Double >

I am getting the following error:

The type 'Double' does not support direct content.

Cannot add content to an object of type "Double".

I feel this is a common problem but not able to find a solution to remove this redundancy.

Update

Thanks Rohit, your answer solved the problem. But I have one more related issue, So updating the question. This variable CalculatedWidth works fine in normal case, but when it is used in RenderTransform it doesn't pick up the value. i.e. If I use the normal way to use Converter it works but it doesn't pick up the variable.

<StackPanel.RenderTransform>
    <TranslateTransform x:Name="SliderTransform">
        <TranslateTransform.X>
            <Binding Converter="{StaticResource PanelConverter}" ElementName="SliderPanel" Path="ActualWidth" /> // Works
            <Binding Path="Width" Source="{StaticResource CalculatedWidth}"/> // Doesn't Work
        </TranslateTransform.X>
    </TranslateTransform>
</StackPanel.RenderTransform>

I have kept the variable as part of the local resource. Does this mean the variable doesn't get created when Render transform is called?

Was it helpful?

Solution

As the error suggest you can't bind with Double. Binding can be done with only Dependency properties.

Instead use FrameworkElement in resource and bind its Width(DP) like this:

<FrameworkElement x:Key="CalculatedWidth">
    <FrameworkElement.Width>
        <MultiBinding Converter="{StaticResource multiplyConverter}">
            <Binding Path="ActualHeight" ElementName="ExpanderContent"/>
            <Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
        </MultiBinding>
     </FrameworkElement.Width>
</FrameworkElement>

and you can bind with this resource like in this sample:

<TextBlock Width="{Binding Width, Source={StaticResource CalculatedWidth}}"/>

OTHER TIPS

A System.Double doesn't implements INotifyPropertyChange (and doesn't show a Value property to notify on) nor it implements dynamic properties advanced binding mechanisms. So it cannot notify of its changes.

The problem with local resources is their instanciation : they do not have visibility to hosting namescope because they are instanciated outside it. So doesn't bind to nothing and the binding returns DependancyProperty.UnsetValue.

The is relative to the FrameworkElement resource itself and returns its Tag property value: null.

If you use VS2013 with .NET 4.5 (maybe it works also with VS2012/.NET 4.0), look at Output window for data binding trace :

System.Windows.Data Warning: 4 : Cannot find source for binding with reference 'ElementName=ExpanderContent'. BindingExpression:Path=ActualHeight; DataItem=null; target element is 'FrameworkElement' (Name=''); target property is 'Width' (type 'Double')

Distinct solutions are offered to you : you can move the FrameworkElement outside the local resources (remember that you probably have to add HorizontalAlign="Left" to allow Width changes. Another solution is to add a dependancy property to the code behind.Finally, you want to share the result of your multiplier converter between more than one control (or properties): The simplest way is maybe to bind it the first property of the first control and to bind other controls properties to this first property.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top