WPF TextBlock MultiDataTrigger Grid.Column.Style doesn't work - wpf

I have a TextBlock and I have a MultiDataTrigger defined as, if both properties are false, then I want the TextBlock to move to an other grid column. Problem is the entire style doesn't work at all. It doesn't even set the default Grid.Column to 5. Please help. Making an edit to the post, the first two textblocks are collapsed and shown correctly
<TextBlock
Name="PlateBarcodeTextBlock"
Grid.Column="3"
Text="{Binding Barcode}"
Visibility="{Binding ShowBarCodeForPlate,
Converter={StaticResource boolToVisibility}}" />
<!--Plate Size-->
<TextBlock
Name="PlateSizeTextBlock"
Grid.Column="4"
Style="{StaticResource PlateSizeDisplayStyle}"
Visibility="{Binding ShowSelectedPlateSize,
Converter={StaticResource boolToVisibility}}"/>
<TextBlock
Name="ProtocolNameTextBlock"
Text="{Binding ProtocolName}" >
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Grid.Column" Value="5"></Setter>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ShowBarCodeForPlate}"
Value="False"/>
<Condition Binding="{Binding ShowSelectedPlateSize}"
Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Grid.Column" Value="3"></Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

Related

change properties inside datatemplate of listboxItem if selected

I have the following style:
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock x:Name="Text" Text="{Binding Name}" Margin="0, 5" FontSize="16"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
I want to change the foreground color of "Text" if the "ListBoxItem" is selected. I know from here: Change WPF DataTemplate for ListBox item if selected how to change the DataTemplate. but since I just want to change colors, this solution makes unnecessary duplication in codd - It would be a greater problem if my DataTemplate would be very complex and long.
How do I achieve change of a single property of an object inside the DataTemplate?
If you actually want the same item template always (whether the item is selected or not), but you want a different foreground color when the item is selected, that's easy. Don't set the ContentTemplate in a trigger, because ContentTemplate doesn't change. Just set the foreground color with a trigger. If you don't mess with the foreground color in the template, it will inherit whatever the ListBoxItem has for that property.
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock
x:Name="Text"
Text="{Binding Name}"
Margin="0, 5"
FontSize="16"
/>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
A more elaborate version of the same style:
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse
Height="12"
Width="12"
VerticalAlignment="Center"
x:Name="Ellipse"
Fill="Yellow"
Stroke="DeepSkyBlue"
StrokeThickness="1"
/>
<TextBlock
x:Name="Text"
Text="{Binding Name}"
Margin="5,5,0,5"
FontSize="16"
/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True"
>
<Setter
TargetName="Ellipse"
Property="Stroke"
Value="Orange"
/>
<Setter
TargetName="Ellipse"
Property="StrokeThickness"
Value="3"
/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>

How to access Control Template controls outside using XAML?

I want to use a NumercUpDown value designed inside a ControlTemplate in another NumericUpDown DatatTrigger, to set up its maximum value based on a condition.
Code -1
<ControlTemplate x:Key="OrderInfo" TargetType="ContentControl">
<TextBlock Grid.Row="0" Grid.Column="0" Style="{StaticResource TextBlockStyle}">Limit Price:</TextBlock>
<i:NumericUpDown Grid.Row="0" Grid.Column="1" x:Name="Price" i:Skin.IsPrice="True" RoundingDecimalPlaces="{Binding Source={StaticResource PriceFormat}, Path=MaxDecimalPlaces}" DisplayFormat="{Binding Source={StaticResource PriceFormat}, Path=StringFormat}" Minimum="0" Increment="{Binding Path=PriceIncrement.Value, TargetNullValue=1}" IncrementCount="{Binding Path=PriceIncrementCount.Value}">
<i:NumericUpDown.Style>
<Style TargetType="i:NumericUpDown" BasedOn="{StaticResource BasicStyle}">
<Setter Property="Value" Value="{Binding Path=Price.Value, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Price.IsAvailable}" Value="False">
<Setter Property="Value" Value="{Binding Path=Price.EstimatedPrice, Mode=OneWay}" />
</DataTrigger>
</Style.Triggers>
</Style>
</i:NumericUpDown.Style>
</i:NumericUpDown>
</Grid>
</ControlTemplate>
Want to use the above Price element in the below Data Trigger
<i:NumericUpDown Grid.Row="0" Grid.Column="3" x:Name="CompletionPrice"
Value="{Binding Path=ExternalAlgoProperties[(i:Description)CompletionPrice].Value,
ValidatesOnExceptions=True, ValidatesOnDataErrors=True}" IsEnabled="True"
RoundingDecimalPlaces="0" Increment="1" Minimum="0">
<i:NumericUpDown.Style>
<Style TargetType="i:NumericUpDown" BasedOn="{StaticResource BasicStyle}">
<Setter Property="Maximum" Value="0"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Side.Code,ConverterParameter={x:Static i:SideCodes.Sell}, Converter={StaticResource EqualsConverter},UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="Maximum" Value="{Binding ElementName=Price,Path=Text,UpdateSourceTrigger=PropertyChanged}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</i:NumericUpDown.Style>
</i:NumericUpDown>
USe Ancestor Binding to access
<DataTrigger
Binding="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type i:NumericUpDown }},
Path=value}"
Value="True">
//Set property
</DataTrigger>

Using DataTrigger for TextBlock HorizontalAlignment property

On my Grid I Have TextBlock and Button.
If Button is not visible I want my TextBlock.HorizontalAlignment to be set to Center.
If Button is visible I want my TextBlock.HorizontalAlignment to be set to Right. Here is my code:
<TextBlock Grid.Row="0" VerticalAlignment="Center" Name="myTextBlock" Text="{Binding TileTextId}" TextWrapping="Wrap" TextAlignment="Center" >
<TextBlock.Triggers>
<DataTrigger Binding="{Binding ElementName=myButton, Path=IsVisible}" Value="True">
<Setter Property="HorizontalAlignment" Value="Right" />
</DataTrigger>
</TextBlock.Triggers>
</TextBlock>
I get the error:
'HorizontalAlignment' member is not valid because it does not have a qualifying type name.
So I tried to add TextBlock.HorizontalAlignment, like this:
<TextBlock Grid.Row="0" VerticalAlignment="Center" Name="myTextBlock" Text="{Binding TileTextId}" TextWrapping="Wrap" TextAlignment="Center" >
<TextBlock.Triggers>
<DataTrigger Binding="{Binding ElementName=myButton, Path=IsVisible}" Value="True">
<Setter Property="TextBlock.HorizontalAlignment" Value="Right" />
</DataTrigger>
</TextBlock.Triggers>
</TextBlock>
I get the error:
XamlParseException
How should I do that?
Don't try to use TextBlock.Triggers, instead go for a Style with Style.Triggers.
<StackPanel>
<TextBlock Text="TextBlock Content" Margin="5">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=myButton,Path=IsVisible}" Value="True">
<Setter Property="HorizontalAlignment" Value="Right"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<Button x:Name="myButton" Content="Click Me!" Margin="5"/>
</StackPanel>
Take note of the documentation, as it mentions, why style triggers are needed here.
Note that the collection of triggers established on an element only
supports EventTrigger, not property triggers (Trigger). If you require
property triggers, you must place these within a style or template and
then assign that style or template to the element either directly
through the Style property, or indirectly through an implicit style
reference.
Try to do this with Style
<TextBlock Grid.Row="0" VerticalAlignment="Center" Name="myTextBlock" Text="{Binding TileTextId}" TextWrapping="Wrap" TextAlignment="Center" >
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=myButton, Path=IsVisible}" Value="True">
<Setter Property="HorizontalAlignment" Value="Right" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

wpf combobox with not focused empty text

I'm using framework 4.0.
How to display grayed text in editable combobox when it is empty and not focused like in picture
UPDATE:
There is no direct way to implement in WPF except using a TextBlock and ComboBox and laying them over each other.
<Grid HorizontalAlignment="Left" Height="21.545" VerticalAlignment="Top" Width="120.964" Margin="56.958,108.962,0,0">
<ComboBox IsEditable="True" Name="myComboBox" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120">
<!--Items Here-->
</ComboBox>
<TextBlock Text="Please Select" IsHitTestVisible="False" Foreground="Gray" x:Name="textBlock" HorizontalAlignment="Left" TextWrapping="Wrap" Margin="3.993,2.664,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Setters>
<Setter Property="Visibility" Value="Hidden" />
</Style.Setters>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Text, ElementName=myComboBox, Mode=OneWay}" Value=""/>
<Condition Binding="{Binding IsKeyboardFocusWithin, ElementName=myComboBox, Mode=OneWay}" Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Visibility" Value="Visible" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
Sorry about this. I misunderstood the question previously. This answer is for UWP.
I think placeholder text is what you are looking for. Check this out ComboBox.PlaceholderText property in MSDN Docs.

WPF Trigger for IsSelected in a DataTemplate for ListBox items

I have a listbox, and I have the following ItemTemplate for it:
<DataTemplate x:Key="ScenarioItemTemplate">
<Border Margin="5,0,5,0"
Background="#FF3C3B3B"
BorderBrush="#FF797878"
BorderThickness="2"
CornerRadius="5">
<DockPanel>
<DockPanel DockPanel.Dock="Top"
Margin="0,2,0,0">
<Button HorizontalAlignment="Left"
DockPanel.Dock="Left"
FontWeight="Heavy"
Foreground="White" />
<Label Content="{Binding Path=Name}"
DockPanel.Dock="Left"
FontWeight="Heavy"
Foreground="white" />
<Label HorizontalAlignment="Right"
Background="#FF3C3B3B"
Content="X"
DockPanel.Dock="Left"
FontWeight="Heavy"
Foreground="White" />
</DockPanel>
<ContentControl Name="designerContent"
Visibility="Collapsed"
MinHeight="100"
Margin="2,0,2,2"
Content="{Binding Path=DesignerInstance}"
Background="#FF999898">
</ContentControl>
</DockPanel>
</Border>
</DataTemplate>
As you can see the ContentControl has Visibility set to collapsed.
I need to define a trigger that causes the Visibility to be set to "Visible"
when the ListItem is selected, but I can't figure it out.
Any ideas?
UPDATE: Of course I could simply duplicate the DataTemplate and add triggers
to the ListBox in question to use either one or the other, but I want to prevent duplicating this code.
You can style your ContentControl such that a trigger fires when its container (the ListBoxItem) becomes selected:
<ContentControl
x:Name="designerContent"
MinHeight="100"
Margin="2,0,2,2"
Content="{Binding Path=DesignerInstance}"
Background="#FF999898">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger
Binding="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}},
Path=IsSelected}"
Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
Alternatively, I think you can add the trigger to the template itself and reference the control by name. I don't know this technique well enough to type it from memory and assume it'll work, but it's something like this:
<DataTemplate x:Key="ScenarioItemTemplate">
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding
RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}},
Path=IsSelected}"
Value="True">
<Setter
TargetName="designerContent"
Property="Visibility"
Value="Visible"/>
</DataTrigger>
</DataTemplate.Triggers>
...
</DataTemplate>
#Matt, Thank you!!!
Just had to add a trigger for IsSelected == false as well,
and now it works like a charm!
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>

Resources