How to directy use RenderTransform property of TextBlock - wpf

I understand I can rotate text like this:
<TextBlock Text="4:00">
<TextBlock.RenderTransform>
<RotateTransform Angle="-90"/>
</TextBlock.RenderTransform>
</TextBlock>
But how can I use the RenderTransform property of TextBlock directly like:
<TextBlock Text="4:00" RenderTransform="<How does this work?>"/>
to avoid the inner code? Maybe a general tutorial for how this works would be good as well.

RenderTransform property is of type Transform which can mean many possible transform types. So you can`t assign it to some type that has some properties using just a string by default.
If you want to to conserve space though, you can define your RotateTransform in resources, and give it some key:
<Window.Resources>
<RotateTransform x:Key="myRotateTransform" Angle="-90" />
</Window.Resources>
Then just use it like that:
<TextBlock Text="4:00" RenderTransform="{StaticResource myRotateTransform}" />
This will work even better if you need to apply same transform to several controls too, because you can edit it in just one place.

Related

WPX/XAML: How can I use TemplateBinding to define a converter in a UserControl?

I have two controls that contain identical markup, except that they require different converters.
LeftHeader.xaml snippet:
<Path.RenderTransform>
<RotateTransform Angle="{Binding IsToggled, Converter={x:Static local:LeftHeader.GlyphAngleConverter}}"/>
</Path.RenderTransform>
RightHeader.xaml snippet:
<Path.RenderTransform>
<RotateTransform Angle="{Binding IsToggled, Converter={x:Static local:RightHeader.GlyphAngleConverter}}"/>
</Path.RenderTransform>
I thought I could create a UserControl with a DependencyProperty of type IValueConverter called "GlyphAngleConverter" and this markup:
<UserControl x:Class="GlyphControl"
<UserControl.Template>
<ControlTemplate>
...
<Path.RenderTransform>
<RotateTransform Angle="{Binding IsToggled, Converter={TemplateBinding GlyphAngleConverter}}"/>
</Path.RenderTransform>
...
</ControlTemplate>
</UserControl.Template>
</UserControl>
The header controls would then use the new control and set GlyphAngleConverter basically like they used before:
New LeftHeader.xaml snippet:
<GlyphControl GlyphAngleConverter="{Binding Source={x:Static local:LeftHeader.GlyphAngleConverter}}"/>
New RightHeader.xaml snippet:
<GlyphControl GlyphAngleConverter="{Binding Source={x:Static local:RightHeader.GlyphAngleConverter}}"/>
But I get the exception "Unable to cast object of type 'System.Windows.TemplateBindingExpression' to type 'System.Windows.Data.IValueConverter'."
What am I doing wrong and/or is there a better approach?
As pointed out in the comments, "You can not bind the Converter of a Binding.".
My solution: create a UserControl with a DependencyProperty of type double called "GlyphAngle" and use that in the header controls, e.g.:
<GlyphControl GlyphAngle="{Binding IsToggled, Converter={x:Static local:LeftHeader.GlyphAngleConverter}}"/>
So, instead of passing the converter into the control, I'm passing the converted value.
You could try defining your converter as a resource.
Do so in a resource key merged in app.xaml. Then define your "other" converter in the the resources of one of the usercontrols, with the same key that is in a resource key merged in app.xaml.
If you have two resources with the same key then whichever is the most local will be found.
The "local" converter will be found in one usercontrol and the global in the other.

Difficulties binding colors for WPF ComboBoxItem ItemTemplate with TemplateBinding

I'm trying to implement a simple combo box (bound to a list of strings) that shows each item as the string label on the right and icon (which is in the form of a GeometryDrawing) on the left. I want the items in the box to inherit the colors I'm using because I've got a custom scheme (with a dark background and white text).
I am able to use TemplateBinding (binding to to ComboBoxItem.Foreground) to make the colors of the text label appear properly but am not able to do the same for the Geometry drawing and I can't figure out why.
Here an image of what I am trying to achieve.
Note that the icon shows up nicely to the left of the name. This only works if I explicitly specify "White" as the brush of the GeometryDrawing.
Below is the XAML I'm using to do make this work.
<tk:RadComboBox ItemsSource="{Binding PostAnalysisRoutines}"
Grid.Row="8" Grid.Column="2"
Text="{Binding Settings.PostCaptureAnalysisRoutine, Mode=TwoWay}">
<!--
Each item in the box is a horizontal stackpanel with an icon for
the routine on the left and the routine name on the right
-->
<tk:RadComboBox.ItemTemplate>
<DataTemplate DataType="sdk:AnalysisRoutine">
<StackPanel Orientation="Horizontal">
<Image Width="30" Height="30">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<!-- ***FORCE TO USE "White" here WHY???*** -->
<GeometryDrawing Brush="White"
Geometry="{Binding Converter={StaticResource PathGeometryConverter}}"
/>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<!-- *** BUT ITS OK TO USE TemplateBinding HERE. WHY??? *** -->
<Label Foreground="{TemplateBinding tk:RadComboBoxItem.Foreground}"
Background="{TemplateBinding tk:RadComboBoxItem.Background}"
Content="{Binding}"/>
</StackPanel>
</DataTemplate>
</tk:RadComboBox.ItemTemplate>
</tk:RadComboBox>
A couple of notes:
I am using Telerik's RadComboBox here but I see a similar problem if I switch this over to regular WPF ComboBox.
I am able to use TemplateBindings for the Label's foreground and background colors to bind to the ComboBoxItem. Those work fine.
The PathGeometryConverter just takes the string name and finds a predefined PathGeometry resource for it.
Unfortunately I am NOT a able to use that same TemplateBinding for the GeometryDrawing's "Brush" property. When I try...
<GeometryDrawing Brush="{TemplateBinding tk:RadComboBoxItem.Foreground}"
Geometry="{Binding Converter={StaticResource PathGeometryConverter}}"
/>
I end up with this:
Therefore I am forced to explicitly specify "White" as the brush color for the
Geometry drawing to make this work.
What is the proper way to make my GeometryDrawing in my template "inherit" the surrounding color scheme...? Is there some sort of TemplateBinding I am missing?
I think your problem is because you're using templatebinding combined with something that is coming out of a resource and or because it's several levels down from the thing being templated. If the geometry was directly in the template then I think it'd work.
What I suggest is you instead try a binding with relativesource and ancestortype tk:RadComboBoxItem, path=foreground.
Or relativesource templatedparent.
I would also use a path rather than an image. It might make very little difference in this case but paths can be sharper. You can bind the Data of a Path to a Geometry resource. Or at least I think you can, I usually set them to a dynamic or staticresource directly.

Switch data template based on value of bound data in Silverlight / WPF

say I am using WPF or Silverlight and binding a ContentPresenter to an integer property:
<ContentPresenter Content={Binding Score} />
and if the score is 10 I want to display a gold star, and otherwise just display the number. So essentially I have two possible data templates:
<Path Fill="Gold" Data="..." />
<TextBlock Text="{Binding Score}" />
What is the best way to set this up? Is it to use a Binding Converter? Or bind to a different object that dynamically loads the appropriate data template xaml and makes the correct FrameworkElement depending on the value of Score? Or is there another trick I am missing - perhaps ContentPresenter isn't the right control to be using?
I wondered if you could do something like this, but it doesn't like the nested binding within the ContentTemplate value:
<StackPanel>
<StackPanel.Resources>
<DataTemplate x:Key="LowScore">
<TextBlock Text="{Binding Path=Score}" Foreground="Red" />
</DataTemplate>
<DataTemplate x:Key="HighScore">
<Path Fill="Gold" Data="M 0,0 l 10,0 l 5,-10 l 5,10 l 10,0 l -7,10 l 2,10 l -10,-5 l -10,5 l 2,-10 Z" />
</DataTemplate>
</StackPanel.Resources>
<ContentPresenter Content="{Binding Score}" ContentTemplate="{StaticResource ResourceKey={Binding ScoreTemplate}}">
</ContentPresenter>
</StackPanel>
you could use a template selector. Here is a nice tutorial on Switch On The Code. Basically, a template selector allows you to select the template for an item based on whatever conditions you want.
Possible solutions:
Create a DataTemplate with a StackPanel containing both control types and bind their Visibility (or use a DataTrigger) so that only one is visible at a time. This is fairly simple and can be good if there are not many states or the differences are small.
Use a DataTemplateSelector and look up the DataTemplate by resource.

How to bind ScaleTransformation.X to slider in Silverlight 3

I need to zoom Canvas. In WPF it is possible to bind ScaleTransformation.X to slider.Value.
I'm not able to do the same in Silverlight - some errors.
Is it supported in SL3?
Thank you.
The reason this doesn't work is that in SL3 the binding target needs to be a FrameworkElement. (This restriction is lifted in SL4 but that doesn't help right now).
However the solution just takes a little lateral thinking (or in this case backward thinking). The source object does not need to be a Framework element. So the answer is reverse the binding, that is put the binding on the Slider Value property and put it in to TwoWay mode.
<Border Width="200" Height="200">
<Border.RenderTransform>
<ScaleTransform x:Name="TargetTransform" />
</Border.RenderTransform>
<!-- Some Content Here -->
</Border>
<Slider Value="{Binding ScaleX, ElementName=TargetTransform, Mode=TwoWay}"
Width="200" Canvas.Top="250"
Minimum="0.1" Maximum="2.0" />

Accessing a RenderTransform in a DataTemplate in Silverlight

I've got a bunch of ContentControls with a DataTemplate like so:
<DataTemplate>
<Canvas>
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.0" ScaleY="1.0"/>
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>
</DataTemplate>
...and I want to change their scales dynamically. I'm new to .NET, so please forgive. I tried to use this technique:
http://msdn.microsoft.com/en-us/library/bb613579.aspx
...but DataTemplates don't appear to have FindName in Silverlight. I then tried binding the Scales like so:
<ScaleTransform ScaleX="{Binding Scale}" ScaleY="{Binding Scale}"/>
...but got a XAML error when I ran.
Am I barking up the wrong tree? I figure this must be possible somehow.
Thank you.
Assuming you don't want to animate the scale, simply include a Scale property in your view model. You cannot access an ancestors DataContext from inside a DataTemplate (WPF supports this, however).
Instead of setting the DataContext of your DataTemplate to your entity, create a wrapper class (ViewModel) that also includes a (INotifyPropertyChanged-firing) Scale property. Now your ContentControl can bind to the Scale property of your view model.

Resources