Saturday, February 19, 2011

silverlight 2 binding data to transforms?

I am working on creating a tag cloud in Silverlight 2 and trying to bind data from a List collection to a Scale transform on a TextBlock. When running this I get an AG_E_PARSER_BAD_PROPERTY_VALUE error. Is it possible to data bind values to transforms in Silverlight 2? If not could I do something to the effect of FontSize={Binding Weight*18} to multiply the tag's weight by a base font size? I know this won't work, but what is the best way to calculate property values for items in a DataTemplate?

<DataTemplate>
<TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Stretch" TextWrapping="Wrap" d:IsStaticText="False" Text="{Binding Path=Text}" Foreground="#FF1151A8" FontSize="18" UseLayoutRounding="False" Margin="4,4,4,4" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
 <TransformGroup>
  <ScaleTransform ScaleX="{Binding Path=WeightPlusOne}" ScaleY="{Binding Path=WeightPlusOne}"/>
 </TransformGroup>
</TextBlock.RenderTransform>

From stackoverflow
  • The issue seems to be Rule #1 from this post:

    The target of data binding must be a FrameworkElement.

    So since ScaleTransform isn't a FrameworkElement it doesn't support binding. I tried to bind to a SolidColorBrush to test this out and got the same error as with the ScaleTransform.

    So in order to get around this you can create a control that exposes a dependency property of your tag data type. Then have a property changed event that binds the properties of your tag data to the properties in the control (one of which would be the scale transform). Here is the code I used to test this out.

    items control:

    <ItemsControl x:Name="items">
      <ItemsControl.ItemTemplate>
        <DataTemplate>
           <local:TagControl TagData="{Binding}" />
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    tag control xaml:

    <UserControl x:Class="SilverlightTesting.TagControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        >
        <TextBlock x:Name="text" TextWrapping="Wrap" FontSize="18" Margin="4,4,4,4">
          <TextBlock.RenderTransform>
              <ScaleTransform x:Name="scaleTx" />
          </TextBlock.RenderTransform>
        </TextBlock>
    </UserControl>
    

    tag control code:

    public partial class TagControl : UserControl
    {
        public TagControl()
        {
            InitializeComponent();
        }
    
        public Tag TagData
        {
            get { return (Tag)GetValue(TagDataProperty); }
            set { SetValue(TagDataProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for TagData.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TagDataProperty =
            DependencyProperty.Register("TagData", typeof(Tag), typeof(TagControl), new PropertyMetadata(new PropertyChangedCallback(TagControl.OnTagDataPropertyChanged)));
    
        public static void OnTagDataPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var tc = obj as TagControl;
            if (tc != null) tc.UpdateTagData();
        }
    
        public void UpdateTagData()
        {
            text.Text = TagData.Title;
            scaleTx.ScaleX = scaleTx.ScaleY = TagData.Weight;
            this.InvalidateMeasure();
        }
    
    }
    

    Seems like overkill for just setting a single property, but I couldn't find an easier way.

  • How do you get the TagControl to acces scaleTx?

0 comments:

Post a Comment