Set or change Converter using a trigger? - wpf

Here is my TextBox with a converter:
<TextBox Text="{Binding TimbraturaSelezionata.OrarioMinuti, Converter={StaticResource Minuti2HHmmConverter}}" Margin="5,0"/>
I searched for a way to set or change the converter only when it is effectively needed.
In fact I would like to put that TextBox inside a general purpose User Control and apply the converter only when a specific condition is met.
The only solution that came to my mind is to use a ContentControl and use two DataTrigger to set its template, one with the Converter inside the TextBox, and one without. I would hope finding a clearer way to achieve my goal.
Thanks for any suggestions.

Since you're set on a trigger. Here's an example. Hope it helps;
<TextBox x:Name="MyTextBox" Text="{Binding TimbraturaSelezionata.OrarioMinuti}" Margin="5,0">
<i:Interaction.Triggers>
<ei:DataTrigger Value="False"
Binding="{Binding YourCondition, ElementName=MyTextBox}">
<ei:ChangePropertyAction PropertyName="Text"
Value="{Binding TimbraturaSelezionata.OrarioMinuti}" />
</ei:DataTrigger>
<ei:DataTrigger Value="True"
Binding="{Binding YourCondition, ElementName=MyTextBox}">
<ei:ChangePropertyAction PropertyName="Text"
Value="{Binding TimbraturaSelezionata.OrarioMinuti, Converter={StaticResource Minuti2HHmmConverter}}" />
</ei:DataTrigger>
</i:Interaction.Triggers>
</TextBox>

Another working solution is the folowing:
<TextBox Width="100">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding ValoreInMinuti}" Value="True">
<Setter Property="Background" Value="Red" />
<Setter Property="Text" Value="{Binding Quantita, Converter={StaticResource Minuti2HHmmConverter}}" />
</DataTrigger>
<DataTrigger Binding="{Binding ValoreInMinuti}" Value="False">
<Setter Property="Background" Value="Yellow" />
<Setter Property="Text" Value="{Binding Quantita}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Note that the Text property is set only via DataTrigger. In my specific case I had only two possibilities, one with the converter and one without it.

Related

How to bind a DataTrigger to a non-bound attribute?

This is not in a template, it is a <Label> in the body of my XAML document. Notice that the Content of the label is set to 'PENDING'. This is monitoring a server connection and at various times the code-behind might change the value of the content to CONNECTED or ERROR. When that happens, I would like for the color of the text to change. I thought this would do it, but it doesn't... all I get is black text.
<Label x:Name="lbl_Connected" Content="PENDING" FontWeight="Bold" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center">
<Label.Style>
<Style TargetType="Label">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self}, Path=Content.Value}" Value="CONNECTED">
<Setter Property="Label.Foreground" Value="Green"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self}, Path=Content.Value}" Value="PENDING">
<Setter Property="Label.Foreground" Value="Yellow"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self}, Path=Content.Value}" Value="ERROR">
<Setter Property="Label.Foreground" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
Can someone tell me how I should be doing this?
Just remove the ".Value" part from the Binding's Path, i.e.:
<DataTrigger Binding="{Binding RelativeSource={RelativeSource self}, Path=Content}" Value="CONNECTED">
<Setter Property="Label.Foreground" Value="Green"></Setter>
</DataTrigger>
Anyway if I were you, I would use a Binding in order to set the Label content and a converter to handle the Foreground color.

How do I bind to the parent's DataContext in a HierarchicalDataTemplate

I have a situation in which I am using a HierarchicalDataTemplate in which most display fields are bound to the items represented in this template (like you'd expect), but I also need one Binding to the data context of the UserControl itself. I fail to manage this last bit.
So I currently have:
<UserControl x:Class="MyProject.ProjectTreeView">
<UserControl.Resources>
<HierarchicalDataTemplate DataType="{x:Type StreetViewModel}"
ItemsSource="{Binding Houses}">
<!-- This Binding works fine (binds to local:StreetViewModel.Street.StreetName) -->
<TextBlock Text="{Binding Street.StreetName}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<!-- THIS BINDING DOESN'T WORK (I want it to bind to local:ProjectTreeView.SelectedStreet) -->
<DataTrigger Binding="{Binding Path=SelectedStreet, RelativeSource={RelativeSource Self}, UpdateSourceTrigger=PropertyChanged}" Value="Main Street">
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
<!-- This one works again (binds to local:StreetViewModel.Street.ConstructionWorkGoingOn) -->
<DataTrigger Binding="{Binding Street.ConstructionWorkGoingOn, UpdateSourceTrigger=PropertyChanged}" Value="true">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</HierarchicalDataTemplate>
So the problematic thing is that I want to access data in ProjectTreeView but can't reach it within this code. I've tried all sort of things with RelativeSource but that doesn't work. How can this be done?
Try :
<DataTrigger Binding="{Binding Path=DataContext.SelectedStreet, RelativeSource={RelativeSource AncestorType=UserControl}}, UpdateSourceTrigger=PropertyChanged}" Value="Main Street">
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>

WPF: Can not find the Trigger target 'cc'. The target must appear before any Setters, Triggers

what is wrong about the following code?
I get this error during compilation:
The property 'TargetName' does not represent a valid target for the 'Setter' because an element named 'cc' was not found. Make sure that the target is declared before any Setters, Triggers or Conditions that use it.
How do I have to refactor my code so I can compile it without error?
I just want to switch a datatemplate with DataTrigger bound to a value in my PersonViewModel!
<ContentControl x:Name="cc" Grid.Column="1">
<DataTemplate>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=CurrentPersonViewModel.IsNew}" Value="True">
<Setter TargetName="cc" Property="ContentTemplate" Value="{DynamicResource NewPersonId}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CurrentPersonViewModel.IsNew}" Value="False">
<Setter TargetName="cc" Property="ContentTemplate" Value="{DynamicResource SelectedPersonId}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl>
Update
You can use a Style for the ContentControl and change the ContentTemplate from there
<ContentControl Name="cc" Grid.Column="1">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{DynamicResource SelectedPersonId}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CurrentPersonViewModel.IsNew}" Value="True">
<Setter Property="ContentTemplate" Value="{DynamicResource NewPersonId}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
UPDATE
I don't understand why the View's in the DataTemplate doesn't inherit the DataContext. Got it working by using this but I can't see why this is necessary
<DataTemplate x:Key="NewPersonId">
<local:NewPersonView DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContentControl}}, Path=DataContext.CurrentPersonViewModel}" />
</DataTemplate>
<DataTemplate x:Key="SelectedPersonId">
<local:SelectedPersonView DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContentControl}}, Path=DataContext.SelectedPersonViewModel}"/>
</DataTemplate>
You do not need the whole DataTrigger stuff.
Just read this to make your DataTemplateSelector work properly:
http://joshsmithonwpf.wordpress.com/2007/03/18/updating-the-ui-when-binding-directly-to-business-objects-that-are-modified/

wpf: override label content when currently bound item is null

I want to set a Label (or TextBox) default string as long as the binding value is null. This works fine for any other property than Content, for example:
<Label Content="{Binding Source={StaticResource pumpCurvesViewSource}, Path=/Label}">
<Label.ContentStringFormat>Details for pump curve: {0}</Label.ContentStringFormat>
<Label.Style>
<Style TargetType="Label" BasedOn="{StaticResource header}">
<Style.Triggers>
<DataTrigger Binding="{Binding Source={StaticResource pumpCurvesViewSource}, Path=/}" Value="{x:Null}">
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
The above will change the background of the label to red as long as there is no CurrentItem in the pumpCurvesViewSource, but what I really want to do is change the background trigger to this:
<Setter Property="Content" Value="No pump curve selected"></Setter>
But this does not work (I'm guessing it is because the Content is already bound and my setting would override the binding).
Does anyone know how to accomplish this?
have you tried TargetNullValue?
<Label Content="{Binding Source={StaticResource pumpCurvesViewSource}, Path=/Label, TargetNullValue='No pump curve selected'}">
If found a way of accomplishing the same thing, but with a bit more code than I liked:
<Label Content="{Binding Source={StaticResource pumpCurvesViewSource}, Path=/Label}">
<Label.ContentStringFormat>Details for pump curve: {0}</Label.ContentStringFormat>
<Label.Style>
<Style TargetType="Label" BasedOn="{StaticResource header}">
<Style.Triggers>
<DataTrigger Binding="{Binding Source={StaticResource pumpCurvesViewSource}, Path=/, Mode=OneWay, Converter={StaticResource isNullConverter}}" Value="True">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<Label Content="No pump curve selected">
<Label.Style>
<Style TargetType="Label" BasedOn="{StaticResource header}">
<Style.Triggers>
<DataTrigger Binding="{Binding Source={StaticResource pumpCurvesViewSource}, Path=/, Mode=OneWay, Converter={StaticResource isNullConverter}}" Value="False">
<Setter Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
the shortest answer would be:
<Label Content="{Binding Source={StaticResource pumpCurvesViewSource, FallbackValue=Your Default String}, Path=/Label}">

Can't update textbox property using DataBinding

I have a custom window which have two depencency properties: Boolean? ValidationStatus, and string ValidationMessage. Binding these properties works fine but trigger doesn't seem to be triggered when these values change. What am I doing wrong?
<TextBlock x:Name="validationTextBox"
Grid.Row="1"
Grid.ColumnSpan="2"
Text="{Binding ElementName=_this, Path=ValidationMessage}"
TextAlignment="Center"
Background="Green">
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Value="False" Binding="{Binding ElementName=_this, Path=ValidationStatus}">
<Setter Property="Panel.Background" Value="Red"/>
<Setter Property="TextBox.Text" Value="Outer checkbox is not checked"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Style Setters do not override local attribute settings. Therefore the data trigger's values are being ignored because you have specified the Text and Background properties on the TextBlock. To fix the problem set the default values of these properties in the style as shown in the following code:
<TextBlock x:Name="validationTextBox"
Grid.Row="1"
Grid.ColumnSpan="2"
TextAlignment="Center">
<TextBlock.Style>
<Style>
<Setter Property="TextBox.Text" Value="{Binding ElementName=_this, Path=ValidationMessage}"/>
<Setter Property="TextBox.Background" Value="Green"/>
<Style.Triggers>
<DataTrigger Value="False" Binding="{Binding ElementName=_this, Path=ValidationStatus}">
<Setter Property="TextBox.Background" Value="Red"/>
<Setter Property="TextBox.Text" Value="Outer checkbox is not checked"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>

Resources