Textblock as Link conditionally - c#

I have a Label with text property bound to a class:
<TextBlock Visibility="Hidden" TextTrimming="WordEllipsis" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Text="{Binding DisplayText}" TextWrapping="Wrap" FontSize="10"></TextBlock>
If that DisplayText is a link than a hyperlink should be used. The class I am binding to also provides the Uri and a boolean isLink. I tried putting a Hyperlink element inside of the Textblock and set its NavigateUri to the Uri from the class but that did not work for me.
Does anyone have a clean solution for this?

You can use both controls and make their visibility change based on isLink property.
<Grid>
<TextBlock>
<Hyperlink NavigateUri="{Binding Uri}"
RequestNavigate="Hyperlink_RequestNavigate">
<TextBlock Text="{Binding DisplayText}"/>
</Hyperlink>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsLink}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Text="{Binding DisplayText}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsLink}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
And in code behind:
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}

I think you can bind a template according to the property.
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding IsLink}" Value="True">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<TextBlock>
<Hyperlink NavigateUri="{Binding DataContext.Url, RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType= ContentControl} }">
<TextBlock Text="{Binding DataContext.DisplayText, RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=ContentControl} }"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding IsLink}" Value="False">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding DataContext.DisplayText,RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=ContentControl} }"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>

Related

WPF Image styles DataTrigger binding not working on change?

I have the following datagrid:
<DataGrid ItemsSource="{Binding PluginItems}" DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}}" x:Name="dtg_Plugins" HorizontalAlignment="Left" VerticalAlignment="Top" Height="315" Width="446" CanUserAddRows="False" AutoGenerateColumns="False" SelectionMode="Single" Padding="0" RowHeight="26">
And it contains column:
<DataGridTemplateColumn CanUserResize="False" CanUserReorder="False" Width="26">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btn_PluginPlay" Padding="0" Height="26" Style="{StaticResource MetroFlatButton}" Background="Transparent" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" Click="btn_PluginPlay_Click">
<Image Width="26" Height="26">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="{StaticResource PlayIcon}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsRunning, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="Source" Value="{StaticResource PlayIcon}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsRunning, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="Source" Value="{StaticResource StopIcon}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I'm not sure why but the DataTrigger to change the image as shown, doesn't work.
The ItemsSource is ObservableCollection, the rest works just fine.
What could be the cause for this?
You only need a single DataTrigger:
<Button x:Name="btn_PluginPlay" Padding="0" Height="26" Style="{StaticResource MetroFlatButton}"
Background="Transparent" VerticalContentAlignment="Top" HorizontalContentAlignment="Left"
Click="btn_PluginPlay_Click">
<Image Width="26" Height="26">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="{StaticResource PlayIcon}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsRunning}" Value="True">
<Setter Property="Source" Value="{StaticResource StopIcon}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>
Then it should work provided that the PluginItem class, or whatever you call it, has a public bool property called IsRunning that raises change notifications whenever it's set to a new value.

Trigger Content of ContentControl

I've got a DataTemplate which looks like this
<DataTemplate DataType="{x:Type viewModel:TreeViewLeafViewModel}">
<StackPanel Orientation="Horizontal">
<Image Name="leafImage"/>
<TextBlock Name="leafTextBlockDisplayName" VerticalAlignment="Center"/>
<TextBlock Name="leafTextBlockKeyGesture" VerticalAlignment="Center"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Row, Converter={StaticResource MatchTypeConverter},
ConverterParameter={x:Type viewModel:TreeViewLeafViewModel}}" Value="True">
<Setter Property="Source" TargetName="leafImage" Value="{Binding Path=Row.Icon, Mode=OneTime}" />
<Setter Property="Text" TargetName="leafTextBlockDisplayName" Value="{Binding Path=Row.DisplayName, Mode=OneTime}" />
<Setter Property="Text" TargetName="leafTextBlockKeyGesture" Value="{Binding Path=Row.KeyGesture.KeyModifierString, Mode=OneTime}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
I would like to replace the leafTextBlockKeyGesture by a TextBox if the IsEditing flag of the corresponding viewmodel is set to true. My Idea was to use a ContentControl inside the DataTemplate and change its Content depending on the IsEditing flag. I tried several solutions but I cannot find a working one.
Does anyone know how to do this?
Based on this answer you need something like this:
<StackPanel>
<StackPanel.Resources>
<DataTemplate x:Key="textbox">
<TextBox Text="edit me"/>
</DataTemplate>
<DataTemplate x:Key="textblock">
<TextBlock Text="can't edit"/>
</DataTemplate>
</StackPanel.Resources>
<CheckBox IsChecked="{Binding IsEditable}" Content="Editable"/>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource textblock}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditable}" Value="true">
<Setter Property="ContentTemplate" Value="{StaticResource textbox}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>

WPF Set label background to image depending on content

I have the following Xaml code and I have label triggers. I want to have a trigger that will place an image in the background for some content value. How do i do this as a trigger?
<Window.Resources>
<DataTemplate x:Key="DataTemplate_Level2">
<Label Content="{Binding }" Width="70" Height="70" HorizontalContentAlignment="Center" x:Name="Background">
</Label>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="1">
<Setter TargetName="Background" Property="Background" Value="Black"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="5">
<Setter TargetName="Background" Property="Background" Value="Image"/>
</DataTrigger>
<DataTrigger Binding="{Binding }" Value="9">
<Setter TargetName="Background" Property="Background" Value="Green"/>
</DataTrigger>
<DataTrigger Binding="{Binding}" Value="7">
<Setter TargetName="Background" Property="Background" Value="blue"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_Level1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_Level2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
Simply use ImageBrush as background.
First add the brush in the resources.
Example:
<Window.Resources>
<ImageBrush x:Key="MyImageBrush"
ImageSource="C:\Test.png" />
</Window.Resources>
Then simply use StaticResource to set it in the specific trigger.
<DataTemplate x:Key="DataTemplate_Level2">
<Label Content="{Binding }"
Width="70"
Height="70"
HorizontalContentAlignment="Center"
x:Name="Background">
</Label>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}"
Value="7">
<Setter TargetName="Background"
Property="Background"
Value="{StaticResource MyImageBrush}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>

Change image of button on click of combobox

I am trying something like this: as my form load I have one image on button (this part work fine) and one check box. When I check checkbox, the image of button should change. I have attached my xaml code with this. Please go through it and suggest changes.
<CheckBox Name="checkbox" Margin="141,148,336,147"/>
<Button Foreground="Black" Height="50" Margin="238,206,179,64">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<StackPanel Orientation="Horizontal">
<Image>
<Image.Style>
<Style>
<Setter Property="Image.Source"
Value="Images/cancel_16.ico" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=checkbox, Path=IsChecked,
RelativeSource={RelativeSource AncestorType=
{x:Type Button}}}" Value="True">
<Setter Property="Image.Source"
Value="Images/cancel_16grayscale.ico" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<ContentPresenter Content="{TemplateBinding Content}"
Margin="5,0,0,0" />
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
Just Remove the RelativeSource and add UpdateSourceTrigger Like this in your style
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=checkbox, Path=IsChecked,UpdateSourceTrigger=PropertyChanged}"
Value="True">
<Setter Property="Image.Source"
Value="Back_jeans.jpg" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=checkbox, Path=IsChecked,UpdateSourceTrigger=PropertyChanged}"
Value="False">
<Setter Property="Image.Source"
Value="Blue_Front_Jeans.jpg" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>

WPF DataTrigger not setting when bound value changed

I have a data template which defines a line to display for every NodePairViewModel drawn inside by a canvas ItemsPanel. The line colour should change when the IsChecked Property of the NodePairViewModel being represented changes as defined in the style (see below) however when this property is set the colour does not change. INotifyPropertyChanged is implemented and I have verified that this event is firing. I cannot see anything obviously wrong and the same setup works for NodeViewModels which are also drawn in the same itemspanel.
<DataTemplate DataType="{x:Type vm:NodePairViewModel}">
<Line Canvas.ZIndex="2" Name="Arc" Stroke="Blue" StrokeThickness="3"
X1="{Binding Path=NodeA.PositionX, Mode=OneWay, Converter={StaticResource NodeLinkXConverter}}"
X2="{Binding Path=NodeB.PositionX, Mode=OneWay, Converter={StaticResource NodeLinkXConverter}}"
Y1="{Binding Path=NodeA.PositionY, Mode=OneWay, Converter={StaticResource NodeLinkYConverter}}"
Y2="{Binding Path=NodeB.PositionY, Mode=OneWay, Converter={StaticResource NodeLinkYConverter}}"
MouseLeftButtonDown="Arc_MouseLeftButtonDown" MouseLeftButtonUp="Arc_MouseLeftButtonUp">
<Line.Style>
<Style TargetType="Line">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked}" Value="True">
<Setter Property="Stroke" Value="Orange"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsSelected, Mode=OneWay}" Value="True">
<Setter Property="Stroke" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsRejected, Mode=OneWay}" Value="True">
<Setter Property="Stroke" Value="LightGray"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsVisited}" Value="True">
<Setter Property="Stroke" Value="LightGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Line.Style>
</Line>
</DataTemplate>
<ItemsControl Name="NodeSpace" ItemsSource="{Binding GraphItems}" Margin="5" MouseMove="NodeSpace_MouseMove" MouseDown="NodeSpace_MouseDown" MouseLeftButtonUp="NodeSpace_MouseLeftButtonUp" MouseLeftButtonDown="NodeSpace_MouseLeftButtonDown" MouseRightButtonDown="NodeSpace_MouseRightButtonDown" RenderTransformOrigin="0.5,0.5" Grid.Column="1" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Name="GraphSurface" Background="#FFFFFE"></Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left">
<Setter.Value>
<Binding Mode="OneWay" Path="PositionX" Converter="{StaticResource XInverseConverter}"/>
</Setter.Value>
</Setter>
<Setter Property="Canvas.Top">
<Setter.Value>
<Binding Mode="OneWay" Path="PositionY" Converter="{StaticResource YInverseConverter}"/>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
And the IsChecked property itself
private bool ArcIsChecked = false;
public bool IsChecked
{
get
{
return ArcIsChecked;
}
set
{
ArcIsChecked = value;
RaisePropertyChanged("IsChecked");
}
}
You need to move default value from Line
<Line ... Stroke="Blue">
into Style as Setter
<Line
Canvas.ZIndex="2"
Name="Arc"
StrokeThickness="3"
X1="{Binding Path=NodeA.PositionX, Mode=OneWay, Converter={StaticResource NodeLinkXConverter}}"
X2="{Binding Path=NodeB.PositionX, Mode=OneWay, Converter={StaticResource NodeLinkXConverter}}"
Y1="{Binding Path=NodeA.PositionY, Mode=OneWay, Converter={StaticResource NodeLinkYConverter}}"
Y2="{Binding Path=NodeB.PositionY, Mode=OneWay, Converter={StaticResource NodeLinkYConverter}}"
MouseLeftButtonDown="Arc_MouseLeftButtonDown"
MouseLeftButtonUp="Arc_MouseLeftButtonUp">
<Line.Style>
<Style TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="Blue"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked}" Value="True">
<Setter Property="Stroke" Value="Orange"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsSelected, Mode=OneWay}" Value="True">
<Setter Property="Stroke" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsRejected, Mode=OneWay}" Value="True">
<Setter Property="Stroke" Value="LightGray"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsVisited}" Value="True">
<Setter Property="Stroke" Value="LightGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Line.Style>
</Line>
according to Dependency Property Setting Precedence List style trigger is lower in hierarchy then local value so it won't be able to overwrite your default (local) value

Categories