views:

2156

answers:

8

Hi,

Anyone know if it's possible to databind the ScaleX and ScaleY of a render transform in Silverlight 2 Beta 2? Binding transforms is possible in WPF - But I'm getting an error when setting up my binding in Silverlight through XAML. Perhaps it's possible to do it through code?

<Image Height="60" HorizontalAlignment="Right" 
       Margin="0,122,11,0" VerticalAlignment="Top" Width="60" 
       Source="Images/Fish128x128.png" Stretch="Fill" 
       RenderTransformOrigin="0.5,0.5" x:Name="fishImage">
    <Image.RenderTransform>
         <TransformGroup>
             <ScaleTransform ScaleX="1" ScaleY="1"/>
             <SkewTransform/>
             <RotateTransform/>
             <TranslateTransform/>
         </TransformGroup>
    </Image.RenderTransform>
</Image>

I want to bind the ScaleX and ScaleY of the ScaleTransform element.

I'm getting a runtime error when I try to bind against a double property on my data context:

Message="AG_E_PARSER_BAD_PROPERTY_VALUE [Line: 1570 Position: 108]"

My binding looks like this:

<ScaleTransform ScaleX="{Binding Path=SelectedDive.Visibility}" 
                ScaleY="{Binding Path=SelectedDive.Visibility}"/>

I have triple verified that the binding path is correct - I'm binding a slidebar against the same value and that works just fine...

Visibility is of type double and is a number between 0.0 and 30.0. I have a value converter that scales that number down to 0.5 and 1 - I want to scale the size of the fish depending on the clarity of the water. So I don't think it's a problem with the type I'm binding against...

+1  A: 

Is it a runtime error or compile-time, Jonas? Looking at the documentation, ScaleX and ScaleY are dependency properties, so you should be able to write

<ScaleTransform ScaleX="{Binding Foo}" ScaleY="{Binding Bar}" />

... where Foo and Bar are of the appropriate type.

Edit: Of course, that's the WPF documentation. I suppose it's possible that they've changed ScaleX and ScaleY to be standard properties rather than dependency properties in Silverlight. I'd love to hear more about the error you're seeing.

Matt Hamilton
A: 

Ah I think I see your problem. You're attempting to bind a property of type Visibility (SelectedDive.Visibility) to a property of type Double (ScaleTransform.ScaleX). WPF/Silverlight can't convert between those two types.

What are you trying to accomplish? Maybe I can help you with the XAML. What is "SelectedDive" and what do you want to happen when its Visibility changes?

Matt Hamilton
A: 

Sorry - was looking for the answer count to go up so I didn't realise you'd edited the question with more information.

OK, so Visibility is of type Double, so the binding should work in that regard.

As a workaround, could you try binding your ScaleX and ScaleY values directly to the slider control that SelectedDive.Visibility is bound to? Something like:

<ScaleTransform ScaleX="{Binding ElementName=slider1,Path=Value}" ... />

If that works then it'll at least get you going.

Edit: Ah, I just remembered that I read once that Silverlight doesn't support the ElementName syntax in bindings, so that might not work.

Matt Hamilton
A: 

@Matt - That's cool - Thanks for helping! Using the edit feature to keep things tight. But see your point about answer count. So adding this one as an answer, and will merge it into the question later...

ElementBinding, like you suggest, is not supported in Silverlight only in WPF... The workaround normally involves creating a "binding helper" (an object that both the scale and the slider binds against). In my case I don't need such a helper, since the SelectedDive.Visibility is the thing that "binds" the slider value and the scale together... :P

I'm afraid this might be a bug in Beta2... Probably have to dumb down the sample to verify.

Jonas Follesø
A: 

Yeah maybe the embedded render transforms aren't inheriting the DataContext from the object they apply to. Can you force the DataContext into them? For example, give the transform a name:

<ScaleTransform x:Name="myScaler" ... />

... and then in your code-behind:

myScaler.DataContext = fishImage.DataContext;

... so that the scaler definitely shares its DataContext with the Image.

Matt Hamilton
I dont think you can give transform tags names
Neo42
A: 

Ok, is the Image itself picking up the DataContext properly?

Try adding this:

<Image Tooltip="{Binding SelectedDive.Visibility}" ... />

If that compiles and runs, hover over the image and see if it displays the right value.

Matt Hamilton
+1  A: 

ScaleTransform doesn't have a data context so most likely the binding is looking for SelectedDive.Visibility off it's self and not finding it. There is much in Silverlight xaml and databinding that is different from WPF...

Anyway to solve this you will want to set up the binding in code**, or manually listen for the PropertyChanged event of your data object and set the Scale in code behind.

I would choose the latter if you wanted to do an animation/storyboard for the scale change.

** i need to check but you may not be able to bind to it. as i recall if the RenderTransform is not part of an animation it gets turned into a matrix transform and all bets are off.

Brian Leahy
A: 

I was hoping to solve this through XAML, but turns out Brian's suggestion was the way to go. I used Matt's suggestion to give the scale transform a name, so that I can access it from code. Then I hooked the value changed event of the slider, and manually updates the ScaleX and ScaleY property. I kept my value converter to convert from the visibility range (0-30m) to scale (0.5 to 1). The code looks like this:

    private ScaleConverter converter;

 public DiveLog()
 {   
  InitializeComponent();

        converter = new ScaleConverter();
        visibilitySlider.ValueChanged += new 
          RoutedPropertyChangedEventHandler<double>(visibilitySlider_ValueChanged);
 }        

    private void visibilitySlider_ValueChanged(object sender,   
                                        RoutedPropertyChangedEventArgs<double> e)
    {
        fishScale.ScaleX = (double)converter.Convert(e.NewValue, 
                                   typeof(double), null, CultureInfo.CurrentCulture);
        fishScale.ScaleY = fishScale.ScaleX;
    }
Jonas Follesø