How to bind tooltip's template Width to TextBox Width? - wpf

My problem is I can't set the width of a TextBox's Tooltip. The tooltip should have the same width as its containing TextBox.
please consider this code :
<TextBox Text="{Binding PatientSubStay.Observations, Mode=OneWay}" ToolTip="{Binding}" x:Name="ObservationsTextBox" MaxLength="100">
<TextBox.Resources>
<Style TargetType="ToolTip">
<Setter Property="Template" Value="{StaticResource ObservationsToolTipControlTemplate}"/>
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}}, Path=Width}"/>
</Style>
</TextBox.Resources>
</TextBox>
The Tooltip is set by a template, and my attempt to modify its Width with a setter is a failure:
thank you.
EDIT:
here is the template (it's a preversion):
<ControlTemplate x:Key="ObservationsToolTipControlTemplate">
<Border Background="White" BorderBrush="Black" BorderThickness="1" Padding="2" CornerRadius="2" MinWidth="150">
<Border.Effect>
<DropShadowEffect BlurRadius="10" ShadowDepth="0"/>
</Border.Effect>
<Grid>
<Grid.ColumnDefinitions>
<!-- Width="{Binding Source={StaticResource TooltipHeaderColumnWidth}}" MaxWidth="{Binding Source={StaticResource TooltipHeaderColumnWidth}}" -->
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
</Grid>
</Border>
</ControlTemplate>
EDIT:
With the setter like the one of Peregrine's answer, I get this rendering:
I wonder why the widths are not equal.
for information, here is the code corresponding to the picture above:
<TextBox Text="{Binding PatientSubStay.Observations, Mode=OneWay}" ToolTip="{Binding}" x:Name="ObservationsTextBox" MaxLength="100">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="{StaticResource FocusedItemSolidColorBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
<TextBox.Resources>
<Style TargetType="ToolTip">
<Setter Property="Template" Value="{StaticResource ObservationsToolTipControlTemplate}"/>
<Setter Property="Width" Value="{Binding PlacementTarget.ActualWidth, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Placement" Value="Bottom"/>
</Style>
</TextBox.Resources>
</TextBox>

The issue is that Tooltips exist outside of the standard visual tree, and so can't reference another control by name or as a typed ancestor. The only thing that a tooltip knows about is its PlacementTarget - the control that it is tied to.
The following code demonstates how to bind to a property of the PlacementTarget
<TextBox Text="Some text for the text box" ToolTip="tool tip">
<TextBox.Resources>
<Style TargetType="{x:Type ToolTip}">
<Setter Property="Width" Value="{Binding PlacementTarget.ActualWidth, RelativeSource={RelativeSource Self}}"/>
</Style>
</TextBox.Resources>
</TextBox>
Note that you should use ActualWidth rather than Width to get the size of another control as Width may not actually be set to a value.

Try setting the ActualWidth of TextBox to the Tooltip. When you don't set the Width (
or Width=Auto) the value is double.NaN. The below code worked for me.
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TextBox}}, Path=ActualWidth}"/>

Related

DataTrigger RelativeSource WPF XAML

The thing I want to make When mouseover in grid Border Visibilty property value must change.
I have a grid with a 3 ColumnDefinition.
The code is
<Grid x:Name="grid1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="27*"/>
<ColumnDefinition Width="93*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="Blue" Visibility="Hidden">
<Border.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver , RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}}" Value="True">
<Setter Property="Border.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
<Image Grid.Column="1" />
<TextBlock Grid.Column="2" />
</Grid>
When mouseover the grid nothing is happen.so This codes not working
one thing is that you should not use IsReadOnly property in DataTrigger when MouseOver is required.
another one is that local value Visibility="Hidden" has higher priority than DataTrigger setter <Setter Property="Border.Visibility" Value="Visible" /> and will not be changed even if condition is true
a fix for both (initial value of Visibility is defined in a setter)
<Border Grid.Column="0" Background="Blue">
<Border.Style>
<Style>
<Setter Property="Border.Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}}" Value="False">
<Setter Property="Border.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
you should also set Grid Background to non-null value (e.g. <Grid x:Name="grid1" Background="Transparent">) for mouse movements to be registered in grid ({x:Null} vs. Transparent?)

WPF Binding Style.Trigger To Parent

I'm trying to implement a Watermark solution for my ComboBoxes I found somewhere on the web (I can't find the page again) but have problems with the binding. The original solution had static text which I would like to replace using a binding to the ComboBoxes Tag property.
This is what I have so far:
<Grid>
<Grid.Resources>
<VisualBrush x:Key="Watermark" TileMode="None" Opacity="0.4" Stretch="None" AlignmentX="Left">
<VisualBrush.Visual>
<TextBlock FontStyle="Italic" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=Tag}"/>
</VisualBrush.Visual>
</VisualBrush>
<Style TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
<Setter Property="Margin" Value="5"/>
<Setter Property="IsEditable" Value="False"/>
<Setter Property="IsReadOnly" Value="True"/>
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Background" Value="{DynamicResource Watermark}"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ComboBox Grid.Column="0" ItemsSource="{Binding Categories}" Tag="Categories"/>
<ComboBox Grid.Column="1" ItemsSource="{Binding SubCategories}" Tag="SubCategories"/>
<ComboBox Grid.Column="2" ItemsSource="{Binding Whatever}" Tag="Whatever"/>
Unfortunately it looks like the "FindAncestor" part is not working.
Can anyone tell me why?
Thanks in advance!
I'm afraid it's not that easy.
First, you cannot set the ComboxBox Background property like this. It becomes obvious, as soon as you try to replace the RelativeSource-Binding by some hardcoded text.
Second, you have to make sure that the VisualBrush ressource is part of the VisualTree of your ComboBox, not somewhere else (in the containing Grid, for example).
Both problems could be solved by retemplating the ComboBox. This can be done in Blend or Visual Studio by first creating a new template (as copy). Then you need to change it a bit.
There will be a Grid named "templateRoot". Add your watermark ressource:
<Grid x:Name="templateRoot" SnapsToDevicePixels="True">
<Grid.Resources>
<VisualBrush x:Key="Watermark" TileMode="None" Opacity="0.4" Stretch="None" AlignmentX="Left">
<VisualBrush.Visual>
<TextBlock FontStyle="Italic" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=Tag}"/>
</VisualBrush.Visual>
</VisualBrush>
</Grid.Resources>
<Grid.ColumnDefinitions>...
Then, at the end of the <ControlTemplate.Triggers> part you need to insert another MultiDataTrigger:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ComboBox}}}" Value="" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" TargetName="templateRoot" Value="{DynamicResource Watermark}"/>
</MultiDataTrigger>
It must be a MultiTrigger condition, because otherwise it's not bindable.

Merge Style.Triggers with property Template in WPF

I want to set a style for my DataGrid, but I do not know where is the problem
the backgroud property does not work with its value in the presence of the Template property.
my code:
<Style x:Key="DataGridStyle1" TargetType="{x:Type DataGrid}">
<Setter Property="CellStyle" Value="{DynamicResource GridStyle1}"/>
</Style>
<Style x:Key="GridStyle1" TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="Background" Value="SeaGreen"/>
</Trigger>
</Style.Triggers>
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Name="DataGridCellBorder">
<ContentControl Content="{TemplateBinding Content}">
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBlock Background="Transparent" TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis"
Height="auto" Width="auto" Text="{Binding Text}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Help me please.
You have explicitly set TextBlock background to Transparent, so it won't pick value from DataGridCell. You should bind with background of DataGridCell using RelativeSource like this:
<TextBlock Background="{Binding Background, RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType=DataGridCell}}"
TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis"
Height="auto" Width="auto" Text="{Binding Text}"/>

DataTrigger on RadioButton IsChecked

I have a scenario where I need to hide some content based on whether a radio button is checked or unchecked. For some reason I can't get this to work the way I expect it to. The behavior is the opposite of what I expect. If I adjust my xaml to accomodate the actual behavior that I'm seeing it everything gets hidden.
Essentially what I have is two radio buttons labeled Fixed and Cycle. When Fixed is checked I want the textbox associated with Fixed to have a visible foreground and the textbox associated with Cycle to have a transparent foreground and vice-versa. What I'm seeing is the exact opposite.
Here's my trigger:
<Grid.Resources>
<Style TargetType="TextBox" x:Key="FixedModeStyle">
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Width" Value="40" />
<Setter Property="Height" Value="20" />
<Setter Property="Margin" Value="10" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,
ElementName=rbtFixedMode}" Value="True" >
<Setter Property="Foreground"
Value="{DynamicResource My.Fonts.Global.LightForeground}" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBox" x:Key="CycleModeStyle">
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Width" Value="40" />
<Setter Property="Height" Value="20" />
<Setter Property="Margin" Value="10" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,
ElementName=rbtCycleMode}" Value="True" >
<Setter Property="Foreground"
Value="{DynamicResource My.Fonts.Global.LightForeground}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
Here's my radio buttons and associated textboxes:
<RadioButton x:Name="rbtFixedMode" Content="Fixed"
GroupName="AveragingMode"
Foreground="{DynamicResource My.Fonts.Global.LightForeground}"
IsChecked="{Binding AveragingWindowMode,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={x:Static Processors:AveragingMode.Fixed}}" />
<DockPanel Grid.Row="1" IsEnabled="{Binding IsChecked, ElementName=rbtFixedMode}">
<TextBox x:Name="txtFixedIntervalLength"
Style="{StaticResource FixedModeStyle}" DockPanel.Dock="Left"
Text="{Binding AveragingWindowFixedLength}" />
</DockPanel>
<RadioButton x:Name="rbtCycleMode" Content="Cycle"
GroupName="AveragingMode" Grid.Row="2"
Foreground="{DynamicResource My.Fonts.Global.LightForeground}"
IsChecked="{Binding AveragingWindowMode,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={x:Static Processors:AveragingMode.Cycles}}" />
<DockPanel Grid.Row="3" IsEnabled="{Binding IsChecked, ElementName=rbtCycleMode}">
<TextBox x:Name="txtCycleIntervalLength"
Style="{StaticResource CycleModeStyle}" DockPanel.Dock="Left"
Text="{Binding AveragingWindowCycleLength}"/>
<TextBlock x:Name="txbCycles" Text="Cycles" Margin="4,10"
Foreground="{DynamicResource My.Fonts.Global.LightForeground}" />
</DockPanel>
Any ideas?
Just making the text transparent is a bad idea, the user will still be able to edit it while it is transparent. Besides that the code is obfuscated and redundant. Do not create two styles for a TextBox, both containing the same setters; create a base-style and use BasedOn for sub-styles.
Not quite sure where your code goes wrong, i would suggest you clean it up, maybe there is some logical error, also here is a working example:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Page.Resources>
</Page.Resources>
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<RadioButton Name="rbCycle" GroupName="g1" Content="Cycle"/>
<RadioButton Name="rbFixed" GroupName="g1" Content="Fixed" Grid.Column="1"/>
<TextBox Grid.Row="1" Text="cycle box">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=rbCycle}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<TextBox Grid.Row="1" Grid.Column="1" Text="fixed box">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Visibility" Value="Hidden"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=rbFixed}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</ScrollViewer>
</Page>
If you're using binding to set the values of your radio buttons, don't use groups. If you're using groups, don't use binding. The two don't play well together.
That may not be the cause of what you're seeing. But I bet it is. And it's certainly interfering with your ability to diagnose the problem, because after you start clicking on buttons their binding doesn't work anymore.

WPF - ListBox ignores Style When ItemsSource is bound

I have created styled a ListBox in WPF so that it is rendered as a checkbox list.
When I populate the ListBox's items manually, the styling works perfectly. However, when I instead bind the ItemsSource of the ListBox to a static resource (an ItemsControl containing the required items), the styling is completely dropped.
Here's the style:
<Style x:Key="CheckBoxListStyle" TargetType="ListBox">
<Style.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>
<ContentPresenter
Grid.Column="1"
Margin="2,0,0,0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
</Style>
Here's the code for the ListBox that shows the style correctly:
<ListBox x:Name="ColumnsList"
Grid.Column="0"
Grid.Row="0"
Style="{StaticResource CheckBoxListStyle}"
BorderThickness="1">
<ListBox.Items>
<ListBoxItem>Test</ListBoxItem>
<ListBoxItem>Test2</ListBoxItem>
<ListBoxItem>Test3</ListBoxItem>
</ListBox.Items>
</ListBox>
Here's the code for the ListBox that ignores the style:
<ListBox x:Name="ColumnsList2"
Grid.Column="0"
Grid.Row="0"
Style="{StaticResource CheckBoxListStyle}"
BorderThickness="1"
ItemsSource="{Binding Source={StaticResource Test1}, Path=Items}">
</ListBox>
Hoping someone can help - I'm pretty new to all this and have tried everything I can think of, but everything I've read leads me to believe that setting ItemsSource should have the same outcome as setting the items manually, so I can't see any reason why this would not work.
Thanks,
AT
Change the Style.Resources to setting the ItemContainerStyle property and it should work like a charm.
<Style x:Key="CheckBoxListStyle" TargetType="ListBox">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>
<ContentPresenter
Grid.Column="1"
Margin="2,0,0,0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
</Style>
In older versions (before SP1), when you define Styles in Style, one of those style will be ignored. Alternatively, you can set the Resources of Style in the parent resources..
Hope this helps!
This is because your TargetType in the CheckListBoxStyle is targetting a ListBoxItem, but when you set the ItemSource property of the ListBox you are binding to a list of other elements (ints for example). This means your target type should be int instead of ListBoxItem.
Alternatively do not specify a target type.

Resources