Set WPF Binding.StringFormat Property on TextBox via Style - wpf

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

Related

TemplatedParent was not set to a child of UserControl

In my project, I have a Usercontrol which contains two child controls say a textbox and a button. A Common Style was written in App.xaml for Textbox. So this style will apply for that usercontrol's Textbox and in tat textbox when i tried to get the TemplatedParent it was null. How do i get the Usercontrol from the Textbox, so that the properties in the Usercontrol can be get in the textbox style.
TemplatedParent can be used within ControlTemplate.
For Style you need to use RelativeSource with mode set to FindAncestor and AncestorType set to UserControl.
Suppose you want to set Text to Name of UserControl from TextBox Style, you can do this way:
<Style TargetType="TextBox">
<Setter Property="Text"
Value="{Binding Path=Name,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=UserControl}}"/>
</Style>

DataBinding inside a ContentTemplate inside a Style in 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

Set parent controls property in xaml

I have a panel with a custom ListView. The ListView's items contains a GroupBox. The GroupBox contains a ListView. This ListView's items contains a GroupBox and so on.
All of the controls above have custom templates and styles
There are ToggleButtons in the Controls VisualTree lowest nodes.
When these buttons are checked I need to disable all the panel except of the button was clicked.
I would like to avoid event chaining through the parents in viewModel classes.
I'm using mvvm pattern and I would like to solve it in the xaml side if its possible.
EDIT: Here is a screenshot and the Pick button should disable the panel
Any suggestions are warmly welcomed.
you need to implement the relative source binding something like below.
IsEnabled="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},Path=IsEnabled}"
Just have a read-only property in your ViewModel that is the negation of the property that your ToggleButton is bound to.
ViewModel:
private Boolean mSourceIsPicked;
public Boolean SourceIsPicked
{
get { return mSourceIsPicked; }
set
{
SetProperty("SourceIsPicked", ref mSourceIsPicked, value);
NotifyPropertyChanged("IsSourceChangeable");
}
}
public Boolean IsSourceChangeable
{
get { return ! this.SourceIsPicked; }
}
Then, in your View, just bind the IsEnabled property of the other controls to that new property.
<ComboBox ItemsSource="{Binding SourceTypes}"
IsEnabled={Binding IsSourceChangeable}" />
The advantage of binding to a property is that you can add/remove controls in your view and just bind to this property without changing additional XAML. You can also change the behavior of any control by not binding to this property.
If you really want a XAML-only solution, you can name each of the controls in the panel, and use a DataTrigger using TargetName on the "SourceIsPicked" property to disable the others:
<ComboBox x:Name="cboSourceTypes" ... />
<ComboBox x:Name="cboSourceNames" ... />
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding SourceIsPicked}" Value="True">
<Setter TargetName="cboSourceTypes"
Property="IsEnabled"
Value="False" />
<Setter TargetName="cboSourceNames"
Property="IsEnabled"
Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Note that this is all freehand, so you may need to adjust it a bit, but it gives you the idea.

How can the ViewModel drive a ControlTemplate?

I have the problem that parts of the TreeView Controltemplate need to change depending on the state of the bound (ItemsSource) ViewModels. For example the little expander icon needs to be exchanged with a different drawing based on each items ViewModel state. Additonally based on the state of each ViewModel the child items need to be arranged horizontally instead of the default vertically.
It sounds like you have to customize ItemsContainerStyle, not ControlTemplate. For example, if you want to mark TreeViewItem as selected whenever underlying ViewModel is selected, you can use the following style:
<TreeView ItemsSource="{Binding ...}
...>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<!-- IsSelected is a property on ViewModel item -->
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Setter .../>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
If Binding doesn't suit you, you can use Converters, Triggers in Style or ControlTemplate. Furthermore, you can also use triggers in DataTemplates.
PS: Wrote the code from head. May have a typo.

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