DataBinding inside a ContentTemplate inside a Style in Silverlight - silverlight

I'm defining the following style in XAML:
<Style TargetType="telerik:RadDiagramShape" x:Key="styleShapeBase">
<Setter Property="Width" Value="120" />
<Setter Property="Height" Value="60" />
<Setter Property="IsResizingEnabled" Value="False" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock x:Name="lblName" Text="{Binding Name}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Then in the code-behind I'm assigning the data context. I want to draw a shape with some text in it that comes from an object (if this end up working I'm going to put more info there). I'm doing it like this:
var shape = new RadDiagramShape();
shape.Style = (Style)Resources["styleShapeBase"];
shape.DataContext = item.DataContext;
Where item is a simple POCO that has a Name property of type string (this part works, I've traced it, i.e. the DataContext is correctly assigned).
But the data binding never occurs. Is it by design (i.e. no data binding inside a content template), if not what's wrong? Thanks,

You can use Bindings in your DataTemplates. In this case, the Binding will look for a Name property on whatever you set as the Content of your RadDiagramShape.
You should ensure that your class has this property and that it is a string.
If that still doesn't work, can you post details of how you set the style and Content of each instance of RadDiagramShape, and of the object you are trying to bind to?
Somewhere in the Control Template for the RadDiagramShape class, there will be a ContentPresenter with its ContentTemplate bound to the one you have defined. The problem is that the ContentTemplate is only used if the Content property is also set. Otherwise nothing will be loaded into that ContentPresenter.
To make this work, you must set the Content property on the instance of this element.
This is a good place to start understanding what the DataContext property is

Related

Set WPF Binding.StringFormat Property on TextBox via Style

I have an WPF application contains many TextBoxes having different kind of Bindings which all share the same StringFormat property (its a technical application, the Textboxes should display values with units "xxx mm"...)
I want to set up the Binding in the XAML/Designer, but I'd like to avoid setting the TextFormat property on every individual Binding. Is there a way to do this using Styles?
If I try to set the Binding in a Setter for the Text property like
<Style x:Name="mmtext" TargetType="TextBox" x:Key="mmtext">
<Setter Property="Text" Value="{Binding Path=A,StringFormat={}{0} mm}" />
</Style>
I need to provide a Path in the Setters Value property, and I cannot define any binding in the XAML itself (as this would override the value set in the Style).
Is there a way to set/modify only the StringFormat property in a single Binding (i.e. the Binding for the Text property) using a Style?
Or do I need to look for templating or a custom control?
you could probably bind the DataContext of the textbox rather than the text property
<TextBox DataContext="{Binding Path=A}" />
and then use a setter like
<Style x:Name="mmtext" TargetType="TextBox" x:Key="mmtext">
<Setter Property="Text" Value="{Binding Path=., StringFormat={}{0} mm}" />
</Style>
for a TwoWay binding you will need a converter anyways to get rid of the extra mms

DataTrigger Overflow exception

How can this be an overflow exception...?
<DataTemplate x:Key="ElementTemplate">
<StackPanel Orientation="Horizontal">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource TypeConv}}" Value="{x:Type models:GroupModel}">
<Setter Property="Margin" Value="5 0 0 0"></Setter>
<Setter Property="DataContext" Value="{Binding Model}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBlock Text="{Binding Name}"></TextBlock>
...
<StackPanel/>
<DataTemplate/>
For the reason: this is a template (with at least 25 UI contros) that normally needs Model A as datatype. the DataTemplate is a ListvVew ItemTemplate. But the datatype can be of type Model B. Model B has a property called 'Model', which is of type Model A.
So instead of copy pasting the whole block template and use style triggers or DataTemplate selectors, I just want to change the DataContext (from "{Binding}" to "{Binding Model}")
anyone has some suggestions, a solution?
Thx!
EDIT: the Converter returns the type of the incoming value (the data object itself). that way i can know when Model B is using the template and so to change the DataContext.
A work-around I would suggest to avoid possible recursion between setting the data context and triggering the DataTrigger:
Have both ModelA and ModelB implement a common interface called IListViewModel for example with a single property getter:
public interface IListViewModel
{
ModelA Model {get;}
}
Then, ModelA's implementation will return this, while ModelB's implementation returns this.ModelA The DataTemplate simply binds to the .Modelof whichever view model it's given.

Style is being overridden when value uses Binding

I have two styles set in my UserControl.Resources
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="white" />
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="white" />
</Style>
So that in my DataTemplate (and note that I chopped the rest off) I will have white text applied without having to change the properties on each and every Label and TextBlock element.
<DataTemplate x:Key="FileTransferItemTemplate">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Label Content="Transferring With: " />
<TextBlock Text="{Binding Path=OtherUserName, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
What happens though(and this caused me a long nightmare where I thought I was databinding improperly because I couldn't see any changes), is when the data is bound the foreground color defaults to black. My databound text was black on a black background, and I didn't even realize for the longest time.
The only way I can override this is manually setting the Foreground="White" on the TextBlock. The Label works fine for the color, because it's not databound.
Why is this happening, and how can I fix it?
The problem is not related to binding. It just seems that the lookup of an externally defined default style from inside a DataTemplate only works for elements that are derived from Control. Since TextBlock isn't derived from Control, your default style is not found.
This page cites the following two statements given by Microsoft:
This behavior is 'By Design' and this is why. Templates are viewed as
an encapsulation boundary. Elements produced by these templates fall
within this boundary. And lookup for a style with a matching
TargetType stops at this boundary. Hence the TextBlock in the repro
which is produced through a template does not pick up the Style in
question. Whereas the TextBlock defined outside the template does.
One way to work around this problem is to give an explicit name to the
Style and reference the style by this name on the TextBlock within the
template.
and
Templates are viewed as an encapsulation boundary when looking up an
implicit style for an element which is not a subtype of Control.

Style property on Blocks/Inlines - Is there a way to get this?

I'm using the new RichTextBox control in SL4Beta and want to create styles for paragraphs and runs (blocks and inlines). I noticed that I can create a style for a <Block/>, like so:
<Style x:Key="lvl2Paragraph" TargetType="Block">
<Setter Property="FontFamily" Value="Times New Roman"/>
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="FontSize" Value="22"/>
</Style>
But I can't set that to a <Paragraph/> as The member "Style" member is not recognized or not accessible. Like this:
<RichTextBox TextWrapping="Wrap">
<Paragraph Style="{StaticResource lvl2Paragraph}">
Can't set a style for a paragraph.
</Paragraph>
</RichTextBox>
Is there anyway to make "Style" exposed for the RichTextBox? I'm open to all ideas.
Style is a property and mechanism supported by elements that inherit from FrameworkElement. However the contents of RichTextBox are lightweight, they do not have FrameworkElement or even UIElement in their class ancestory.
The only way I can think of to mitigate this is to create an Attached property to take the place of the missing Style property. However you would have implement in that attached property all the setting of the other properties. It would sensitive to document order if inline Xaml also sets the same properties.

Can my WPF Style Setter use a TemplateBinding?

I'm trying to do something like this...
<Style
x:Key="MyBorderStyle"
TargetType="Border">
<Setter
Property="Padding"
Value="{TemplateBinding Padding}" />
</Style>
...but I get the error:
'Padding' member is not valid because it does not have a qualifying type name.
How do I provide a "qualifying type name"?
Note: The reason I'm trying to do this, is that I'd like to include the same Border in a series of similar ControlTemplates.
I also tried this:
<Setter
Property="Padding"
Value="{TemplateBinding GridViewColumnHeader.Padding}" />
...and it actually compiled, but then when I ran the app, I got a XamlParseException:
Cannot convert the value in attribute 'Value' to object of type ''.
I thought maybe qualifying Padding with GridViewColumnHeader (which is the ControlTemplate I want to use this style with) would work, but no dice.
EDIT:
Well, according to the documentation for TemplateBinding, it says:
Links the value of a property in a control template to be the value of some other exposed property on the templated control.
So it sounds like what I'm trying to do is just plain impossible. I really would like to be able create reusable styles for certain controls in my control templates, but I guess the template bindings cannot be included in these styles.
TemplateBinding should work for the case where you're templating a control and you want to bind the value of a property of that control to a property of a different control inside the template. In your case you're templating something (call it MyControl), and that template will include a border whose Padding should be bound to MyControl's padding.
From MSDN documentation:
A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with {Binding RelativeSource={RelativeSource TemplatedParent}}.
But for whatever reason, specifying TemplatedParent as the source for the binding doesn't seem to work within Style Setters. To get around that you can specify the relative parent to be an AncestorType of the control you're templating (which effectively finds the TemplatedParent providing you haven't embedded other MyControls in the MyControl template).
I used this solution when I was trying to custom template a Button control in which the (String) Content of the Button needed to be bound to the Text property of a TextBlock in the ControlTemplate for the button. Here's what that code looked like:
<StackPanel>
<StackPanel.Resources>
<ControlTemplate x:Key="BarButton" TargetType="{x:Type Button}">
<ControlTemplate.Resources>
<Style TargetType="TextBlock" x:Key="ButtonLabel">
<Setter Property="Text" Value="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type Button}} }" />
</Style>
</ControlTemplate.Resources>
<Grid>
<!-- Other controls here -->
<TextBlock Name="LabelText" Style="{StaticResource ButtonLabel}" />
</Grid>
</ControlTemplate>
</StackPanel.Resources>
<Button Width="100" Content="Label Text Here" Template="{StaticResource BarButton}" />
</StackPanel>
The {TemplateBinding ...} shortcut is not available in a Setter.
But nobody will stop you using the full verbose version such as:
Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Padding}".
A property can be qualified simply by prefixing it with the type name. For example, Border.Padding instead of Padding.
However, I'm not sure it makes sense for your scenario. TemplateBindings are used inside a control template.

Resources