WPF: How to bind to another control's child's child properties - wpf

Problem:
I have two separate objects in a grid: A TextBox, and a TextBlock
I want the TextBlock to be visible when the vertical scrollbar of the TextBox is visible.
Update : The vertical scrollbar visibility should be set to Auto, so it is the actual visibility (see below) we want to trigger on.
Approach:
The template of the TextBox seems to contain a Grid named PART_InnerGrid which in turn contains a scrollviewer named PART_ContentHost. This scrollviewer contains a property called ComputedVerticalScrollBarVisibility which is of type Visibility.
I have tried creating a trigger on the TextBlock, but I have been unable to construct a proper binding path. How would I do this:
<TextBox x:Name="TB1" TextWrapping="Wrap" AcceptsReturn="True" MinHeight="40" VerticalScrollBarVisibility="Auto"/>
<TextBlock Text="VISIBLE" Grid.Row="1" VerticalAlignment="Bottom">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=TB1, Path=(PART_InnerGrid).(PART_ContentHost).ComputedVerticalScrollBarVisibility}">
<DataTrigger.Setters>
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>

You could bind both of their visibility to a boolean property and use a Converter to convert the boolean to a visibility value.
Their visibility would look like this:
Visibility="{Binding YourBoolProperty, Converter={StaticResource Converters_BoolToVisConverter}}"

<StackPanel>
<TextBox Text="text" Width="50" VerticalScrollBarVisibility="Hidden" x:Name="TextBox"/>
<TextBlock Text="ScrollViewer visible">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=TextBox, Path=VerticalScrollBarVisibility}" Value="Visible">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>

Related

WPF - When TextBox inside DateTemplate is focused change datatemplate child property

I have a listview with a Border wrapping a textbox (and other elements not shown in sample code). I want when the textbox is keyboard focused to change a property of the border that wraps it.
<ListView ItemsSource="{Binding activeLists}">
<ListView.ItemTemplate>
<DataTemplate>
<Border x:Name="border">
<TextBox Text="something">
<TextBox.Style>
<Style>
<Style.Triggers>
<Trigger Property="TextBox.IsFocused" Value="True">
<Setter TargetName="border" Property="TextBox.Background" Value="Red"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
If using inside the trigger TargetName="border" the item is not found.
If possible to do this from XAML only.
When I tried running this, I also got the error "TargetName property cannot be set on a Style Setter". Which indicates that you can't set a property of the Border control inside a style setter for the TextBox control (which doesn't honestly surprise me.)
What you can do instead is set it in the style of the border control itself, using a DataTrigger to bind to the IsFocused property of the textbox:
<Border>
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsFocused, ElementName=textBox}" Value="true">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBox Name="textBox" Text="something"/>
</Border>

WPF Showing / Hiding a control with triggers

I'm new to WPF and I trying to create xaml logic to show / hide a control based on the value of the AllowMiscTitle on the ViewModel. The xaml consist of two fields a combobox of the standard tiles ("Mr", "Mrs", ..., "Other") when "Other" is selected I want the textbox to display.
I've created the follow xaml:
<DockPanel Validation.Error="Validation_Error" HorizontalAlignment="Stretch">
<ComboBox ItemsSource="{Binding Path=Titles, Mode=OneTime}"
Text="{Binding Path=Title}"/>
<TextBox x:Name="TxtBxTitle" Margin="5,5" Visibility="Visible">
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=AllowMiscTitle}" Value="false">
<Setter Property="TextBox.Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</DockPanel>
That Trigger won't work because you have set Visibility property explicitly in TextBox
Do it like this:
<TextBox x:Name="TxtBxTitle" Margin="5,5">
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=AllowMiscTitle}" Value="false">
<Setter Property="TextBox.Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The reason for this is Dependency property value precedence.
There is a
<BooleanToVisibilityConverter x:Key="BoolToVis"></BooleanToVisibilityConverter>
You can use it as following
<TextBox Visibility="{Binding YourPropertyName, Converter={StaticResource BoolToVis}}"></TextBox>
If I got your question right:-
If your selected value is binded to some property in the ViewModel like:-
private string _GenderType;
public string GenderType
{
get
{
return _GenderType;
}
set
{
_GenderType= value;
RaisePropertyChanged("GenderType");
In xaml:-
<TextBox.Style>
<Style>
<Setter Property="TextBox.Visibility" value="Hidden"/>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=GenderType,ElementName=Combo1}" Value="Other">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>

Can't bind to property of one control in a DataTrigger to other control in different grids

I have two controls in this example but in the real application i have many more whick depending of the value of the property Content of a Label in Grid one (for example), some other Labels, TextBoxes, TextBlocks and Buttons will be Visible or Collapsed in Grid two (for example).
But to simplify my problem i will have a simplified example...
<Grid Name="gridOne">
<Label Content="{Binding Collection.Name}" Name="lblCaption"/>
</Grid>
<Grid Name="gridTwo">
<Label Content="My Label" Visibility="Collapsed">
<Label.Style>
<Style TargetType="Label">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lblCaption, Path=Content}" Value="Employers">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<TextBox Text="{Binding EmployerName}" Visibility="Collapsed">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lblCaption, Path=Content}" Value="Employers">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
I know that this won't work too if i set the property Visibility as Collapsed for default in control but i have many collections and i don't think that having one DataTrigger for each Collection is good way to achieve it. Anyway one problem comes when binding controls in different grids and other in handling the property Visibility in a good way.
Thanks in advance!
Local value takes precedence over style triggers. Move the visibility intialization inside the style as:
<Label Content="My Label">
<Label.Style>
<Style TargetType="Label">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lblCaption, Path=Content}" Value="Employers">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>

WPF Listbox - Empty List Display Message

Can anyone suggest the best way to display a Textblock (with a text such as "List Empty") so that it's visibility is bound to the Items.Count.
I have tried the following code and can't get it to work, so think that I must be doing it wrong.
<ListBox x:Name="lstItems"
ItemsSource="{Binding ListItems}">
</ListBox>
<TextBlock Margin="4" FontStyle="Italic" FontSize="12" Text="List is empty" Visibility="Collapsed">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lstItems, Path=Items.Count}" Value="0">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
The problem in your code is that setting the value of Visibility in the text block itself has higher priority than setting it in the style. So, even when the trigger occurs, the setting inside the trigger has no effect. Change the XAML to:
<TextBlock Margin="4" FontStyle="Italic" FontSize="12" Text="List is empty" >
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lstItems, Path=Items.Count}" Value="0">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Where the setting of Visibility is all in the style and it works (at least in my demo project).

How to make a text box Visibility=Hidden with a trigger

I seem to be having a hard time today. All I want to do is make a TextBox hidden of visible based on a bool value databound to the Window its hosted in.
What I have just won't compile and I don't understand why. Please help.
<TextBlock Grid.Column="2" Text="This order will be sent to accounting for approval"
Foreground="Red" VerticalAlignment="Center" FontWeight="Bold" Padding="5">
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=AllowedToSubmit}" Value="True">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
You need to set the Style.TargetType in order for it to recognize the Visibility property:
<TextBlock Grid.Column="2" VerticalAlignment="Center" FontWeight="Bold" Foreground="Red" Padding="5" Text="This order will be sent to accounting for approval">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=AllowedToSubmit}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Your binding path to AllowedToSubmit probably needs to have ElementName set to the Window's name, as well.
Another option is to bind TextBlock.Visibility directly to the property:
<Window>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
</Window.Resources>
<TextBlock Visibility="{Binding Path=AllowedToSubmit, Converter={StaticResource BoolToVisibility}}" />
</Window>
If you want it to work like in your sample, where true hides the TextBlock, then you can write your own converter to convert opposite of the built-in BooleanToVisibilityConverter.

Resources