Is it possible to use templates within templates?
For instance, I have the following two templates:
<HierarchicalDataTemplate
x:Key="RecursiveTemplate"
ItemsSource="{Binding Children}">
<StackPanel Margin="1" Orientation="Horizontal">
<Ellipse Fill="DarkGreen" Width="14" Height="14"/>
<TextBlock
MouseDown="OnTreeMouseDown"
TargetUpdated="OnTargetUpdated"
Visibility="{Binding Editing, Converter={StaticResource visibilityInverter}}"
Margin="5"
Text="{Binding Name}"/>
<TextBox
PreviewKeyDown="OnTreeKeyDown"
Visibility="{Binding Editing, Converter={StaticResource visibilityConverter}}"
Margin="2"
Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
x:Key="ContainerTemplate"
ItemsSource="{Binding Children}">
<StackPanel Margin="1" Orientation="Horizontal">
<Ellipse Fill="DarkBlue" Width="14" Height="14"/>
<TextBlock
MouseDown="OnTreeMouseDown"
TargetUpdated="OnTargetUpdated"
Visibility="{Binding Editing, Converter={StaticResource visibilityInverter}}"
Margin="5"
Text="{Binding Name}"/>
<TextBox
PreviewKeyDown="OnTreeKeyDown"
Visibility="{Binding Editing, Converter={StaticResource visibilityConverter}}"
Margin="2"
Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
There's a section of identical XAML:
<TextBlock
MouseDown="OnTreeMouseDown"
TargetUpdated="OnTargetUpdated"
Visibility="{Binding Editing, Converter={StaticResource visibilityInverter}}"
Margin="5"
Text="{Binding Name}"/>
<TextBox
PreviewKeyDown="OnTreeKeyDown"
Visibility="{Binding Editing, Converter={StaticResource visibilityConverter}}"
Margin="2"
Text="{Binding Name}"/>
Is it possible to move that to a resource and refer to it by name, rather than repeat it?
The answer appears to be "almost"
<Style x:Key="textBlockStyle" TargetType="TextBlock">
<Setter Property="Visibility" Value="{Binding Editing, Converter={StaticResource visibilityInverter}}"/>
<Setter Property="Margin" Value="4"/>
<Setter Property="Text" Value="{Binding Name}"/>
<EventSetter Event="MouseDown" Handler="OnTreeMouseDown"/>
</Style>
<Style x:Key="textBoxStyle" TargetType="TextBox">
<Setter Property="Visibility" Value="{Binding Editing, Converter={StaticResource visibilityConverter}}"/>
<Setter Property="Margin" Value="1"/>
<Setter Property="Text" Value="{Binding Name, NotifyOnSourceUpdated=True}"/>
<EventSetter Event="PreviewKeyDown" Handler="OnTreeKeyDown"/>
</Style>
Then the templates reduce to
<HierarchicalDataTemplate
x:Key="RecursiveTemplate"
ItemsSource="{Binding Children}">
<StackPanel Margin="1" Orientation="Horizontal">
<Ellipse Fill="DarkGreen" Width="14" Height="14"/>
<TextBlock
Style="{StaticResource textBlockStyle}"/>
<TextBox
SourceUpdated="OnSourceUpdated"
Style="{StaticResource textBoxStyle}"/>
</StackPanel>
</HierarchicalDataTemplate>
However, note you cannot put SourceUpdated in a style, as it's not covered by EventSetter
Related
I am new to Xaml and somehow i got stuck here. I googled a lot of different approaches but neither did work :-( I hope someone has here has an idea and can help me :-)
With the help of a few tutorials in the internet I got this TreeView. It works like a charme :-)
<TreeView>
<TreeViewItem ItemsSource="{Binding Data.Number}">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Width="15" Margin="5 0 5 0" Source="image.ico"/>
<TextBlock Text="{Binding Data.ID}"/>
<TextBlock Text=" [" Foreground="Blue"/>
<TextBlock Text="{Binding Data.Number.Count}" Foreground="Blue"/>
<TextBlock Text="]" Foreground="Blue"/>
</StackPanel>
</TreeViewItem.Header>
<TreeViewItem.ItemTemplate>
<DataTemplate>
<TreeViewItem Header="{Binding ItemID}">
<TreeViewItem ItemsSource="{Binding ItemInfo}">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Width="15" Margin="5 0 5 0" Source="image.ico"/>
<TextBlock Text="Items"/>
<TextBlock Text=" [" Foreground="Blue"/>
<TextBlock Text="{Binding ItemInfo.Count}" Foreground="Blue"/>
<TextBlock Text="]" Foreground="Blue"/>
</StackPanel>
</TreeViewItem.Header>
<TreeViewItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value.Number}"/>
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
<TreeViewItem ItemsSource="{Binding SetInfo}">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Width="15" Margin="5 0 5 0" Source="image.ico"/>
<TextBlock Text="Sets"/>
<TextBlock Text=" [" Foreground="Blue"/>
<TextBlock Text="{Binding SetInfo.Count}" Foreground="Blue"/>
<TextBlock Text="]" Foreground="Blue"/>
</StackPanel>
</TreeViewItem.Header>
<TreeViewItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value.ID}"/>
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
<TreeViewItem ItemsSource="{Binding GroupInfo}">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image Width="15" Margin="5 0 5 0" Source="image.ico"/>
<TextBlock Text="Groups"/>
<TextBlock Text=" [" Foreground="Blue"/>
<TextBlock Text="{Binding GroupInfo.Count}" Foreground="Blue"/>
<TextBlock Text="]" Foreground="Blue"/>
</StackPanel>
</TreeViewItem.Header>
<TreeViewItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value.Number}"/>
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
</TreeViewItem>
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
</TreeView>
The problem is now that I want the selected item (with mouse click) gets bold. But only the selected item (not items below or above). It doesnt matter on which level the item is.
I tried this a lot of variations but none did work. This two were the best ones but they always select a hole node or just the top node and I couldnt break it down for one single node.
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
<Setter Property="FontWeight" Value="Normal"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}, FallbackValue=False}" Value="True">
<Setter Property="TextBlock.FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
Can you try this Style?
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="FontWeight" Value="Normal"/>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.Resources>
I have an hierarchical Treeview which each item contains a complexed entity which consists of:
Border
-- Check box
-- TextBlock
i want to change the opacity of the border whenever the checkbox IsEnabled property is set to "False"
this is what i have:
<HierarchicalDataTemplate DataType="{x:Type sd:LegendTreeViewItem}" ItemsSource="{Binding Path=SubSensors}">
<Border x:Name="treeViewItemBorder" Height="24" Margin="3 3 3 3" Width="350" Background="{Binding Path=Color}" CornerRadius="8 8 8 8">
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="treeViewItemCheckbox" Margin="5 5 5 5" Click="CheckBox_Click" IsChecked="{Binding IsChecked}" VerticalAlignment="Center" IsEnabled="{Binding Enabled}" Style="{StaticResource OpacityOnDisabled}"/>
<TextBlock Height="Auto" FontFamily="Tahoma" FontWeight="Bold" Foreground="Black" HorizontalAlignment="Left" Text="{Binding Path=Name}"
VerticalAlignment="Center" ToolTip="{Binding Path=Name}"/>
</StackPanel> </Border>
</HierarchicalDataTemplate>
<TreeView x:Name="legendTypeTree" Grid.Row="1" Foreground="White" ItemsSource="{Binding ElementName=uc, Path=TypeItemsSource}">
<TreeView.Resources>
<Style x:Key="OpacityOnDisabled" TargetType="{Binding RelativeSource={RelativeSource AncestorType=Border}}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="Border.Opacity" Value="0.3"/>
<Setter Property="Border.Background" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.Resources>
</TreeView>
Move both HierarchicalDataTemplate and Style for the Border in the TreeView resources. (Style first in order for the StaticResource OpacityOnDisabled to resolve properly).
You want to change the style of the border, so there is no sense to apply style on the checkbox. Move Style="{StaticResource OpacityOnDisabled}" from the CheckBox to the Border element. Set the correct type of the style and for the DataTrigger change the bindinig to Binding="{Binding ElementName=treeViewItemCheckbox, Path=IsChecked}"
In the end you should have something like, which should do what you want:
Result:
<TreeView
x:Name="legendTypeTree"
Grid.Row="1"
Foreground="White"
ItemsSource="{Binding ElementName=uc, Path=TypeItemsSource}">
<TreeView.Resources>
<Style x:Key="OpacityOnDisabled" TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=treeViewItemCheckbox, Path=IsChecked}" Value="False">
<Setter Property="Border.Opacity" Value="0.3"/>
<Setter Property="Border.Background" Value="White"/>
</DataTrigger>
</Style.Triggers>
</Style>
<HierarchicalDataTemplate DataType="{x:Type sd:LegendTreeViewItem}" ItemsSource="{Binding Path=SubSensors}">
<Border
x:Name="treeViewItemBorder"
Height="24"
Margin="3 3 3 3"
Width="350"
Background="{Binding Path=Color}"
CornerRadius="8 8 8 8"
Style="{StaticResource OpacityOnDisabled}">
<StackPanel Orientation="Horizontal">
<CheckBox
x:Name="treeViewItemCheckbox"
Margin="5 5 5 5"
Click="CheckBox_Click"
IsChecked="{Binding IsChecked}"
VerticalAlignment="Center"
IsEnabled="{Binding Enabled}" />
<TextBlock
Height="Auto"
FontFamily="Tahoma"
FontWeight="Bold"
Foreground="Black"
HorizontalAlignment="Left"
Text="{Binding Path=Name}"
VerticalAlignment="Center"
ToolTip="{Binding Path=Name}"/>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
I have a data grid built using DataGridTemplateColumns. When a validation error exists, we are displaying it on the Textblock of the CellTemplate. When scrolling occurs, the error styling is lost after it scrolls off the page.
In my control resources:
<ControlTemplate x:Key="validationTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Foreground="Yellow"
FontSize="20"
VerticalAlignment="Center"
Margin="0,0,2,2">!</TextBlock>
<Border Grid.Column="1"
BorderBrush="Yellow"
BorderThickness="1"
Margin="0"
Padding="0"
Height="19">
<AdornedElementPlaceholder/>
</Border>
</Grid>
</ControlTemplate>
<Style x:Key="TextBlockValidationStyle" TargetType="{x:Type TextBlock}">
<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 Within the DataGrid:
<DataGridTemplateColumn Header="Destination Column">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox IsEditable="True"
IsTextSearchCaseSensitive="{Binding ElementName=caseSensitiveSearch, Path=IsChecked}"
ItemsSource="{Binding AllSuggestedNames}"
TextSearch.TextPath="SuggestedName"
Text="{Binding ColumnMapping.DestinationColumnName, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource TextBlockValidationStyle}"
Text="{Binding ColumnMapping.DestinationColumnName,
ValidatesOnDataErrors=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource validationTemplate}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Solved it! Wrapping each CellTemplate's interior of their DataTemplate with an AdornerDecorator fixed it right up!
<DataTemplate>
<AdornerDecorator>
<TextBlock Style="{StaticResource TextBlockValidationStyle}"
Text="{Binding ColumnMapping.DestinationColumnName,
ValidatesOnDataErrors=True,
NotifyOnValidationError=True,
UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{StaticResource validationTemplate}"/>
</AdornerDecorator>
</DataTemplate>
Ok I have an XElement that looks like:
<authentication mode="Forms">
<forms loginUrl="login.aspx" name=".LOGIN" protection="All" timeout="4800" path="/" />
</authentication>
Then in my XAML I setup a ContentControl that looks like:
<ContentControl Content="{Binding Data}">
<ContentControl.ContentTemplate>
<DataTemplate>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Attribute[mode].Value}" Value="Forms">
<Setter Property="ContentTemplate" Value="{StaticResource FormsTemplate}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
Where Data is my public property that contains the XElement. My template looks like:
<DataTemplate x:Key="FormsTemplate">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Login URL"/>
<TextBox Text="{Binding Path=Element[forms].Attribute[loginUrl].Value}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name"/>
<TextBox Text="{Binding Path=Attribute[name].Value}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Protection"/>
<TextBox Text="{Binding Path=Attribute[protection].Value}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Timeout"/>
<TextBox Text="{Binding Path=Attribute[timeout].Value}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Path"/>
<TextBox Text="{Binding Path=Attribute[path].Value}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="passport">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Redirect URL"/>
<TextBox Text="{Binding Path=Attribute[redirectUrl].Value}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
Why doesn't this work? Nothing shows up on the screen when I do this.
I solved it by using a Style Trigger instead. Below is what I had to use for this to work.
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Data.Attribute[mode].Value}" Value="Forms">
<Setter Property="ContentTemplate" Value="{StaticResource FormsTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.Attribute[mode].Value}" Value="Passport">
<Setter Property="ContentTemplate" Value="{StaticResource PassportTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
I have an AccordionControl (WPFToolkit) to which I add items dynamically:
<my:Accordion Grid.Column="1"
ItemsSource="{Binding Path=Tests}"
SelectionMode="ZeroOrOne"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<my:Accordion.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Header}" />
</StackPanel>
</DataTemplate>
</my:Accordion.ItemTemplate>
<my:Accordion.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Content}"/>
</DataTemplate>
</my:Accordion.ContentTemplate>
</my:Accordion>
To actually see the Content, I have to select (open) an AccordionItem, close it and open it again. What could be the reason for this behaviour?
EDIT
I have found a way around this using styles instead, still I would be interested why the above does not work. Here the style solution:
<Style x:Key="itemStyle" TargetType="my:AccordionItem">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="accordionStyle" TargetType="my:Accordion">
<Setter Property="ItemContainerStyle" Value="{StaticResource itemStyle}" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ItemsControl ItemsSource="{Binding MenuItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Text, Mode=OneWay}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<my:Accordion Grid.Column="1" Height="Auto"
Name="accordion1"
ExpandDirection="Left"
SelectionMode="One"
ItemsSource="{Binding Tests}"
Style="{StaticResource accordionStyle}">
</my:Accordion>
EDIT
I have now found the problem: I cannot "Stretch the AccordionControl.
<my:Accordion Grid.Column="1" Height="Auto"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Name="accordion1"
ExpandDirection="Left"
SelectionMode="One"
ItemsSource="{Binding Tests}"
Style="{StaticResource accordionStyle}">
</my:Accordion>
As soon as I do this, it is not working anymore. Does someone know a way around this?