Changing DataTemplate based on Attribute in an XElement - wpf

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>

Related

WPF: Single TreeViewItem bold

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>

Conditional DataTemplate for Images

Trying to use the same control for displaying a column with images and without, depending on a boolean (HistoryOn). Next xaml code works, but always shows the images.
<DataGridTemplateColumnx:Name="dgtc">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding
Converter={StaticResource myDataRowToListConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border x:Name="imageBorder" BorderThickness="1" BorderBrush="Black"
MouseLeave="imageBorder_MouseLeave"
MouseEnter="imageBorder_MouseEnter"Height="16">
<Image x:Name="myImage" Source="{BindingMyImagePath}"
MouseUp="Image_MouseUp" HorizontalAlignment="Center">
</Image>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Next xaml code displays only the path, not the images. What is wrong?
<DataGridTemplateColumn x:Name="dgtc">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding
Converter={StaticResource myDataRowToListConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding MyImagePath}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding HistoryOn}" Value="true">
<Setter Property="ContentTemplate"
Value="{StaticResource imagesOff}" />
</DataTrigger>
<DataTrigger Binding="{Binding HistoryOn}" Value="false">
<Setter Property="ContentTemplate"
Value="{StaticResource imagesOn}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
In the Windows.Resources:
<DataTemplate x:Key="imagesOn">
<Border x:Name="imageBorder1" BorderThickness="1" BorderBrush="Black"
MouseLeave="imageBorder_MouseLeave"
MouseEnter="imageBorder_MouseEnter"Height="16">
<Image x:Name="myImage" Source="{BindingMyImagePath}"
MouseUp="Image_MouseUp"HorizontalAlignment="Center">
</Image>
</Border>
</DataTemplate>
<DataTemplatex:Key="imagesOff">
<Border x:Name="imageBorder2" BorderThickness="1" BorderBrush="Black"
MouseLeave="imageBorder_MouseLeave"
MouseEnter="imageBorder_MouseEnter"Height="16">
</Border>
</DataTemplate>
You can use CellTemplateSelector to Choose the desired template depending on the object take a look at this link to see a detailed example on this topic
Good Luck

HierarchicalDataTemplate binding

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>

Wpf DataGrid sub-group style

I am grouping data-grid to two level.I mean each main group have one or many sub groups.
<controls:DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" Style="{DynamicResource newExpanderStyle}" HorizontalAlignment="Left"
Margin="5,0,0,0" VerticalAlignment="Top" Background="{DynamicResource NormalBrushGrid}" >
<Expander.Header>
<StackPanel Background="#E5E5E5" Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" FontWeight="Bold" FontSize="12" Margin="5,0" />
<TextBlock Text="{Binding Path=ItemCount}"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</controls:DataGrid.GroupStyle>
I would like to differentiate sub group from main group.How can i apply different color to sub-group header
Thanks in advance
Chand.
The groups do not provide much information, but if you only have one sublevel you can use CollectionViewGroup.IsBottomLevel to differentiate. e.g.
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Content.IsBottomLevel"/>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</GroupStyle.HeaderTemplate>
The templated parent is a ContentPresenter and the Content of that is an internal group class.

Is it possible to template a template in WPF XAML?

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

Resources