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>
Related
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>
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>
Title says it all
<Page.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<DataTemplate x:Key="level1">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="GroupTitle" FontSize="16" FontWeight="Bold" Foreground="#FF000532" Text="{Binding name}"/>
<TextBlock x:Name="GroupDescription" Text="{Binding description}"/>
<TextBlock x:Name="Depth" Text="{Binding childDepth}"/>
<ItemsControl ItemsSource="{Binding settings}">
</ItemsControl>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="level2">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="GroupTitle" FontSize="16" FontWeight="Bold" Foreground="#FF000532" Text="{Binding name}"/>
<TextBlock x:Name="GroupDescription" Text="{Binding description}"/>
<TextBlock x:Name="Depth" Text="{Binding childDepth}"/>
<ItemsControl ItemsSource="{Binding settings}">
</ItemsControl>
<TabControl ItemsSource="{Binding groups}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" ContentTemplate="{StaticResource level1}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid>
<ContentControl x:Name="SettingsDisplayer" Content="{Binding settingGroup, ElementName=page}">
<ContentControl.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
</ContentControl.Resources>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource level1}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=childDepth}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource level1}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=childDepth}" Value="2">
<Setter Property="ContentTemplate" Value="{StaticResource level2}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=childDepth}" Value="3">
<Setter Property="ContentTemplate" Value="{StaticResource level3}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=childDepth}" Value="4">
<Setter Property="ContentTemplate" Value="{StaticResource level4}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
The getter for childDepth is not even being accessed because I put a console trace in there to know when it is. The property is populated as it shows the proper amount when seen in the Depth TextBlock in the DataTemplates.
The relevant property in my class:
public int childDepth { get { Console.WriteLine(this.getDepth()); return this.getDepth(); } }
No mater what the childDepth is it alwayse skipps the triggers and just uses the level1 template.
I feel silly, So apparently binding the ContentControl's Content is not the equivalent of binding data to the ContentControl, thus I needed to target my DataTrigger Bindings more specifically at my original DP since it doesn't just take the parent containers binding.
This worked:
<DataTrigger Binding="{Binding settingGroup.childDepth, ElementName=page}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource level1}" />
</DataTrigger>
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>
How do you conditionally style treeviewitemson binded properties
I'm running into an issue where I want to style items in a Tree View, those that are valid selections vs hierarchy items.
I've tried to move my style tag into a TreeView.Resources and a TreeView.ItemContainerStyle tag but it still doesn't cause any formatting.
<TabItem Name="Queries" Header="Queries"
d:DataContext="{d:DesignInstance views:QuerySettingsView}">
<Grid>
<TreeView ItemsSource="{Binding QueryTreeModels}"
Width="500" Height="200" VerticalAlignment="Top"
HorizontalAlignment="Center" Margin="0,0,175,0">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style >
<Setter Property="TreeViewItem.IsExpanded"
Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="TreeViewItem.IsSelected"
Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsQuery}">
<Setter Property="TextBlock.Foreground" Value="Chartreuse" />
</DataTrigger>
<DataTrigger Binding="{Binding IsFolder}">
<Setter Property="TextBlock.Foreground" Value="Crimson" />
</DataTrigger>
</Style.Triggers>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</TabItem>
For DataTrigger you need to complete the condition by adding a value to DataTrigger bound field. like <DataTrigger Binding="{Binding IsQuery}" Value="true"> Refer the below code.
<TreeView x:Name="tree" Width="500" Height="200"
VerticalAlignment="Top" HorizontalAlignment="Center"
>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style >
<Setter Property="TreeViewItem.IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="TreeViewItem.IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsQuery}" Value="true">
<Setter Property="TreeViewItem.Foreground" Value="Chartreuse" />
</DataTrigger>
<DataTrigger Binding="{Binding IsFolder}" Value="true">
<Setter Property="TreeViewItem.Foreground" Value="Crimson" />
</DataTrigger>
</Style.Triggers>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<TextBlock Text="{Binding NodeName}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>