Attached Behavior in Trigger Causes Build Error - c#

I have a Style with a control template and I am having trouble getting it to compile. I am trying to trigger an attached behavior. If I put it in the control template triggers it works fine...but if I put it in the textbox triggers I get a build error that says:
Cannot find the static member 'SelectAllProperty' on the type
'TextBoxBehavior'
Here is my code:
<Style x:Key="RenamingTextBox" TargetType="{x:Type TextBox}">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<TextBlock x:Name="block" Visibility="Visible" Text="{TemplateBinding Text}" Margin="0"/>
<TextBox x:Name="box" Visibility="Collapsed" Text="{TemplateBinding Text}" Margin="0">
<TextBox.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.Setters>
<Setter TargetName="box" Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
<!-- This next line gives an error even though it is the same format as the one below -->
<Setter Property="behaviors:TextBoxBehavior.SelectAll" Value="True"/>
</Trigger.Setters>
</Trigger>
</TextBox.Triggers>
</TextBox>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsRenaming}" Value="true">
<DataTrigger.Setters>
<Setter TargetName="block" Property="TextBox.Visibility" Value="Collapsed" />
<Setter TargetName="box" Property="TextBox.Visibility" Value="Visible" />
<!-- Uncommenting below works fine -->
<!--<Setter TargetName="box" Property="behaviors:TextBoxBehavior.SelectAll" Value="True"/>-->
</DataTrigger.Setters>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Any ideas as to why one gives a build error and the other doesn't?

Nevermind, I needed to put the triggers for the textbox in a style instead:
<TextBox x:Name="box" Visibility="Collapsed" Text="{TemplateBinding Text}" Margin="0">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
<Setter Property="behaviors:TextBoxBehavior.SelectAll" Value="True"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

Related

ListBox ItemTemplate update using ToggleButton and attached Property

I want to implement a ListBox with ToggleButton when I press then the template of ListBox should be updated. The template one will have only icons and one will have both icons and text as shown in the image.
I have created one attached property for this and binded it to the ToggleButton IsChecked property inside control template, but this attached property is not updating and my template is not changing.
First time when I load the application it is working.
<Style x:Key="NavigationListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{StaticResource PrimaryDarkBrush}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="SelectedIndex" Value="0"/>
<Setter Property="Width" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border Background="{TemplateBinding Background}"
BorderThickness="0"
Padding="0"
SnapsToDevicePixels="true">
<ScrollViewer Padding="{TemplateBinding Padding}"
Focusable="false">
<StackPanel>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<ToggleButton IsChecked="{Binding local:IsOpenInfo.IsOpen,Mode=TwoWay}" Style="{DynamicResource ToggleButtonstyle}" Foreground="White">
</ToggleButton>
</StackPanel>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate" Value="{DynamicResource NavigationDataTemplate}"/>
<Style.Triggers>
<Trigger Property="local:IsOpenInfo.IsOpen" Value="True">
<Setter Property="ItemTemplate" Value="{DynamicResource NavigationDataTemplate1}"/>
</Trigger>
<Trigger Property="local:IsOpenInfo.IsOpen" Value="False">
<Setter Property="ItemTemplate" Value="{DynamicResource NavigationDataTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="ToggleButtonstyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<StackPanel Orientation="Horizontal">
<iconPacks:PackIconMaterialDesign x:Name="MenuItemIcon" VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="12" Kind="ArrowBack"/>
<TextBlock Text="Collapse" VerticalAlignment="Center" HorizontalAlignment="Center" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="ArrowForward"/>
<Setter TargetName="txtBlock" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="ArrowBack"/>
<Setter TargetName="txtBlock" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="NavigationDataTemplate">
<iconPacks:PackIconMaterialDesign x:Name="MenuItemIcon" VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="12"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="Home">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Home"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Email">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Email"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Cloud">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Cloud"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Collapse">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Mail"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate x:Key="NavigationDataTemplate1">
<StackPanel Orientation="Horizontal">
<iconPacks:PackIconMaterialDesign x:Name="MenuItemIcon" VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="12"/>
<TextBlock Text="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="Home">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Home"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Email">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Email"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="Cloud">
<Setter TargetName="MenuItemIcon" Property="Kind" Value="Cloud"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
The attached property class as below:
public class IsOpenInfo
{
public static bool GetIsOpen(DependencyObject obj)
{
return (bool)obj.GetValue(IsOpenProperty);
}
public static void SetIsOpen(DependencyObject obj, bool value)
{
obj.SetValue(IsOpenProperty, value);
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsOpenProperty =
DependencyProperty.RegisterAttached("IsOpen", typeof(bool), typeof(IsOpenInfo), new PropertyMetadata(true));
}
I am clueless why the attached property not updating when IsChecked property is changed and style triggers not working?
Is there any simple way to achieve this?
Anyone guide me to handle this case?
Your style is defined with TargetType set to ListBox, the triggers will resolve the value of your custom local:IsOpenInfo.IsOpen property for the ListBox instance that your style is applied to.
However, the ToggleButton is defined inside the ControlTemplate of the ListBox. Its IsChecked binding will not automatically set the value of the attached property on its templated parent control. It will be set on the ToggleButton itself. So practically, you are setting the value on the ToggleButton, but you are checking it on the ListBox in the style, so you are operating on different values.
You can make it work by explicitly binding to the TemplatedParent, which is a ListBox instance. Both the style and the toggle button will resolve the attached property value for the same ListBox instance.
<ToggleButton IsChecked="{Binding (local:IsOpenInfo.IsOpen), RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
Style="{DynamicResource ToggleButtonstyle}"
Foreground="White"/>

Show IDataErrorInfo errors in tooltip on keyboard focus and mouse over

I have a TextBox which shows IDataErrorInfo validation information via a ToolTip by using this style:
<Style x:Key="EntityPropertyTextBoxErrorStyle" TargetType="{x:Type TextBox}"
BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<!-- this gets rid of all adornment INCLUDING THE DEFAULT RED BORDER -->
<AdornedElementPlaceholder />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="Background" Value="MistyRose" />
</Trigger>
</Style.Triggers>
</Style>
Now I want the ToolTip to show on keyboard focus as well.
The best solution I found was to use a Popup instead of a ToolTip:
<ControlTemplate x:Key="ErrorTemplate">
<StackPanel>
<AdornedElementPlaceholder x:Name="ControlWithError" />
<Popup PlacementTarget="{Binding ElementName=ControlWithError}" Placement="Top">
<Popup.IsOpen>
<MultiBinding Converter="{StaticResource AtLeastOneTrueConverter}">
<Binding Path="AdornedElement.IsMouseOver"
ElementName="ControlWithError" Mode="OneWay" />
<Binding Path="AdornedElement.IsKeyboardFocusWithin"
ElementName="ControlWithError" Mode="OneWay" />
</MultiBinding>
</Popup.IsOpen>
<Border BorderThickness="1">
<TextBlock Text="{Binding
AdornedElement.(Validation.Errors)[0].ErrorContent,
ElementName=ControlWithError}"
Background="White"
FontSize="8" />
</Border>
</Popup>
</StackPanel>
</ControlTemplate>
<Style x:Key="EntityPropertyTextBoxErrorStyle" TargetType="{x:Type TextBox}"
BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Background" Value="MistyRose" />
</Trigger>
</Style.Triggers>
</Style>

Style Basedon not working with checkbox

I have a style defined in a resource dictionary to make my checkbox look like a button:
<Style TargetType="CheckBox" x:Key="CBCheckBoxButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Border Name="BackgroundBorder" Background="Black" CornerRadius="20">
<Grid>
<Rectangle x:Name="UpperRect" Margin="1" Grid.Row="0" RadiusX="20" RadiusY="20" Fill="{StaticResource GrayGradient}"/>
<TextBlock Name="ButtonContent" Text="{TemplateBinding Content}" Margin="3" VerticalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="UpperRect" Property="Fill" Value="{StaticResource LightBlueGradient}" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="UpperRect" Property="Fill" Value="{StaticResource BlueGradient}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="BackgroundBorder" Property="Background" Value="DarkGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Effect" Value="{StaticResource ShadowEffect}" />
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontFamily" Value="Calibri"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="DarkGray"/>
<Setter Property="Effect" Value="{StaticResource DisableShadowEffect}" />
</Trigger>
</Style.Triggers>
</Style>
When used like so it works great:
<CheckBox Width="80" Height="80" Margin="10" Content="{Binding Y2LockAxisString}" Command="{Binding Y2LockDisableEnableCommand}" Style="{StaticResource CBCheckBoxButton}"/>
But I need to add a style so that different commands etc. are called depending on the state of the check box. So I used the basedon property:
<CheckBox Width="80" Height="80" Margin="10">
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource CBCheckBoxButton}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Command" Value="{Binding ExecuteX2LockDisable}" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Command" Value="{Binding ExecuteX2LockEnable}" />
</Trigger>
</Style.Triggers>
</Style>
</CheckBox>
But the checkbox looks like a default checkbox with none of the appearance elements applied to it.
Why isn't the appearance style working?
It seems you are adding the Style as Content, instead of Style.
Have you tried
<CheckBox Width="80" Height="80" Margin="10">
<CheckBox.Style>
<Style --- snip --->
</Style>
</CheckBox.Style>
</CheckBox>

Change fontweight on button in WPF treeview

I have a templated treeview that is working just as i want, but i have a context menu which allows for a tier 1 node to be marked as "default".
I have a datatrigger which reacts to a property in the viewmodel, which should change the fontweight to bold just to visually show that this is the default node. But the setter will not change the fontweight on the button no matter what!
However if i change another value, like the foreground color for example, it works just fine, font size also no problem.
Why is this, can anyone explain this? Here is some code if needed:
Trigger:
<HierarchicalDataTemplate ItemsSource="{Binding Children,Mode=TwoWay,NotifyOnSourceUpdated=True}">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Image x:Name="nodeImg" Source="{Binding Image}" MaxHeight="16" MaxWidth="16"/>
<Button x:Name="nodeButton" Content="{Binding Name}" Command="{Binding Command}" Style="{StaticResource TreeMenuButton}"/>
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem},Path=IsExpanded}" Value="True">
<Setter TargetName="nodeImg" Property="Source" Value="{Binding ImageExpanded}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding IsDefaultConnection}" Value="True">
<Setter TargetName="nodeButton" Property="FontWeight" Value="Bold"></Setter>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
Default style on button:
<Style x:Key="TreeMenuButton" TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="MinHeight" Value="23" />
<Setter Property="MinWidth" Value="75" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Border"
CornerRadius="0"
BorderThickness="0"
Background="Transparent"
BorderBrush="Transparent">
<ContentPresenter Margin="2"
HorizontalAlignment="Left"
VerticalAlignment="Center"
RecognizesAccessKey="True"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'd be surprised if your code even built as you can't add a DataTrigger into a UIElement.Triggers collection. Try using a Style instead (this definitely works):
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsDefault}" Value="True">
<Setter Property="TextBlock.FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
If by some miracle your DataTemplate does work in a UIElement.Triggers collection, then try using the class name as well as the property name:
<Setter Property="TextBlock.FontWeight" Value="Bold" />

Tooltip is not showing properly

I am new to WPF. I want to show custom tool tip when a error occurs in TextBox. So I have used Style as shown below:
<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Placement="Top">
<Border Margin="-4,0,-4,-3" Padding="2" Background="Red">
<Border.BitmapEffect>
<OuterGlowBitmapEffect></OuterGlowBitmapEffect>
</Border.BitmapEffect>
<Label Foreground="White" FontWeight="Bold" Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type TextBox}}, Path=(Validation.Errors)[0].ErrorContent}"></Label>
</Border>
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Above code is not showing error message in ToolTip. Could you please help m ein this regard? Any help would be highly appreciable.
You should change your current style with the following style (msdn):
<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
And you should create style for ToolTip:
<Style TargetType="ToolTip">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="Placement" Value="Top" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border Name="Border" Margin="-4,0,-4,-3" Padding="2" Background="Red">
<Border.BitmapEffect>
<OuterGlowBitmapEffect></OuterGlowBitmapEffect>
</Border.BitmapEffect>
<ContentPresenter
Margin="4"
HorizontalAlignment="Left"
VerticalAlignment="Top"
TextElement.Foreground="White" TextElement.FontWeight="Bold"
/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasDropShadow" Value="true">
<Setter TargetName="Border" Property="CornerRadius" Value="4"/>
<Setter TargetName="Border" Property="SnapsToDevicePixels" Value="true"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Example of usage:
<TextBox Text="{Binding MyText, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource textBoxInError}"
/>
You should also replace
Path=(Validation.Errors)[0].ErrorContent
with
Path=(Validation.Errors).CurrentItem.ErrorContent}
because in your case you'll get an silent ArgumentOutOfRangeException when there are no validation errors. Don't forget to implement IDataErrorInfo or INotifyDataErrorInfo.

Categories