How to set TabIndex in Hyperlink? - c#

I am new to WPF, I dont know how to do this.
I tried following code -
<TextBlock Grid.Column="3" Grid.Row="3" Visibility="{Binding Path=CanCreate, Converter={StaticResource BoolVisibilityConverter}}">
<Hyperlink KeyboardNavigation.TabIndex="2" Command="{Binding Path=CreateCommand}">Create
<Hyperlink.Style>
<Style TargetType="{x:Type Hyperlink}">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CanCreate, Converter={StaticResource BoolVisibilityConverter}}">
<Setter Property="KeyboardNavigation.IsTabStop" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</Hyperlink.Style>
</Hyperlink>
</TextBlock>
Visibility depends on CanCreate Dependency property. Here IsTabStop is not enabling. Can anyone suggest the solution. Thanks in advance.
Requirement
I want to set TabIndex to hyperlink when it is visible.

You don't need a converter in the DataTrigger change your Hyperlink.Style to:
<Hyperlink.Style>
<Style TargetType="{x:Type Hyperlink}">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CanCreate}" Value="True">
<Setter Property="KeyboardNavigation.IsTabStop" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</Hyperlink.Style>
EDIT: You may also want to remove focus when your TextBlock and Hyperlink is invisible, you can do it by adding another DataTrigger:
<Hyperlink.Style>
<Style TargetType="{x:Type Hyperlink}">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CanCreate}" Value="True">
<Setter Property="KeyboardNavigation.IsTabStop" Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=CanCreate}" Value="False">
<Setter Property="Focusable" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Hyperlink.Style>

Related

XAML DataTrigger Not Firing?

I have a property in my ModularClientModule class called ExistsOnDisk. When that property is set to false, I want to disable the CheckBox. For some reason, this does not seem to work despite me putting it last in the Triggers XAML block, which means it should be the last thing to fire. I.e, nothing should be interfering. I know my code-behind should be correct because as you will see below, I have another control which receives the update and fires fine.
This one here responds to the ExistsOnDisk property change without issue, and strikesthrough the text:
GridViewColumn x:Name="FileNameHeader" Header="File Name">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="{x:Type local:ModularClientModuleUI}">
<TextBlock Text="{Binding Filename}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ExistsOnDisk}" Value="False">
<Setter Property="TextDecorations" Value="Strikethrough"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
This one here does not, and the checkbox remains enabled:
<GridViewColumn x:Name="StatusHeader" Header="Status">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="{x:Type local:ModularClientModuleUI}">
<StackPanel>
<CheckBox x:Name="ClientModuleStatusCheckBox" Margin="5, 0" Click="ClientModuleStatusCheckBox_Click" IsEnabled ="{Binding Client.Online}">
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource MahApps.Styles.CheckBox}">
<Setter Property="IsEnabled" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding LoadState}" Value="Loaded">
<Setter Property="IsChecked" Value="True" />
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding LoadState}" Value="Unloaded">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding LoadState}" Value="Loading">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding ExistsOnDisk}" Value="True">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding ExistsOnDisk}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
What could be going on here?
Set the default value of the IsEnabled using a Setter and remove IsEnabled ="{Binding Client.Online}" from the <CheckBox> element:
<CheckBox x:Name="ClientModuleStatusCheckBox" Margin="5, 0" Click="ClientModuleStatusCheckBox_Click">
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource MahApps.Styles.CheckBox}">
<Setter Property="IsEnabled" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding LoadState}" Value="Loaded">
<Setter Property="IsChecked" Value="True" />
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
<DataTrigger Binding="{Binding LoadState}" Value="Unloaded">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding LoadState}" Value="Loading">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding ExistsOnDisk}" Value="True">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
Also note that you shouldn't use more than one trigger on the same bool property.

Textblock collapsed using space

I have a C# WPF project. I am using an ObservableCollection<T> in my viewmodel class.
I have a ListView in xaml file. There is TextBlock inside the ListView binding to the ObservableCollection<T>.
I want to collapse them by DataTrigger. The result is that those TextBlock is collapsed but still using space. I would like to ask how to fix it?
Here is the ListView I am using:
<ListView Grid.Row="1" ItemsSource="{Binding ServiceObjects}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ServiceName}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Foreground" Value="Black" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsCollapsed}" Value="true">
<Setter Property="Foreground" Value="#FFBF00" />
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Try this:
<Style TargetType="ListBoxItem" x:Key="LstBoxItemStyle">
<Setter Property="MinHeight"
Value="0" />
<Setter Property="IsEnabled"
Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsCollapsed}" Value="True">
<Setter Property="IsEnabled"
Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
and
<ListView Grid.Row="1"
ItemsSource="{Binding ServiceObjects}"
ItemContainerStyle="{StaticResource LstBoxItemStyle}">
Or use filters https://learn.microsoft.com/pl-pl/dotnet/desktop/wpf/data/how-to-filter-data-in-a-view?view=netframeworkdesktop-4.8

Enabling TextBox with trigger

I want a Textbox to be disabled, except the user hovers with the mouse over it. But this does not seam to work, the Textbox is still not editable if I hover over it. (Yes I know that this is unusual.)
What I tried is:
<Border>
<TextBox Text="Hover to edit me!" IsEnabled="False" >
<TextBox.Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Border}, Path=IsMouseOver}" Value="True">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
<!-- this does not work either -->
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="True">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
<!-- neither did this -->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsEnabled" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Border>
I wonder if it is possible at all using a trigger?
This is because of the Dependency Property Value Precedence in WPF.
You need to set the IsEnabled property to false in the Style, so the trigger can override the value.
The local value has always a higher priority, so setting IsEnabled="False" directly in the text box will override any style or style trigger value.
Here is a working example:
<Border>
<TextBox Text="Text">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<DataTrigger
Binding="{Binding IsMouseOver,
RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}"
Value="True">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Border>

Text.IsEmpty Opposite

i have this CheckBox
<CheckBox VerticalAlignment="Center" Name="CheckItem"
IsChecked="{Binding ElementName=Faccette, Path=Text.isEmpty, Mode=OneWay}"
/>
Faccette is a TextBlock, i need the opposite of the Text.isEmpty.
Is it possible without a Converter?
You may use a Style with DataTriggers:
<CheckBox>
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="IsChecked" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Faccette, Path=Text}" Value="">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=Faccette, Path=Text}" Value="{x:Null}">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>

Calling a Image style

Is there any way to create a call'able image style? I have multiple buttons on a user control that have the same button and button image style. I can set the button style so that it can be called from the style (dynamic resource) of the button.
Here is an example of my code and the image style code:
<Grid.Resources>
<Style TargetType="Button"
x:Key="ButtonEditSaveStyle">
<Setter Property="IsEnabled"
Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding CanEdit}"
Value="True">
<Setter Property="IsEnabled"
Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Button Width="32"
Height="22"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Name="gdEmployeeInfo_btnUpdateRecord"
Click="gdEmployeeInfo_btnUpdateRecord_Click"
Style="{DynamicResource ResourceKey=ButtonEditSaveStyle}"/>
I want to set my code up so that I can have the call above an have an additional call or a combined call to set the image style as well. I know I can have the image style in the button (as shown in this next code), but I want to have one place to update multiple buttons using the same style setup. Image style code:
<Image>
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source"
Value="edit_32.png" />
<Setter Property="Stretch"
Value="Uniform" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditing}"
Value="True">
<Setter Property="Source"
Value="save_smallest.png" />
<Setter Property="Stretch"
Value="Uniform" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
Figured out the answer to my question. This set of code allows me to use dual style setting while creating only one call for the button's style:
<!--SaveEditImageSwitch-->
<Image x:Key="SaveEditImage" x:Shared="False">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source"
Value="edit_32.png" />
<Setter Property="Stretch"
Value="Uniform" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditing}"
Value="True">
<Setter Property="Source"
Value="save_smallest.png" />
<Setter Property="Stretch"
Value="Uniform" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<!--ButtonEditSaveStyle-->
<Style TargetType="Button"
x:Key="ButtonEditSaveStyle">
<Setter Property="IsEnabled"
Value="False" />
<Setter Property="Content"
Value="{DynamicResource ResourceKey=SaveEditImage}" />
<Style.Triggers>
<DataTrigger Binding="{Binding CanEdit}"
Value="True">
<Setter Property="IsEnabled"
Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
<Button Width="32"
Height="22"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Name="gdEmployeeInfo_btnUpdateRecord"
Click="gdEmployeeInfo_btnUpdateRecord_Click"
Style="{DynamicResource ResourceKey=ButtonEditSaveStyle}">

Categories