Passing BitmapImage as Tag to DataTemplate - wpf

I'm a bit unexperienced in WPF and trying to get a simple Template in WPF for a button with an Image icon in addition to text to work.
Style code:
<Style x:Key="DatabaseButtonWithImageTag" TargetType="Button" BasedOn="{StaticResource DatabaseButton}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Width="100" Source="{TemplateBinding Tag}" />
<ContentControl Grid.Column="1" Content="{TemplateBinding Content}" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
View code:
<Image Source="{StaticResource image_new_patient}"/>
<Button Style="{StaticResource DatabaseButtonWithImageTag}" Tag="{StaticResource image_new_patient}" Width="150" Height="100">
Test!
</Button>
The image outside the button is displayed, so is "Test!", but there is no image inside the button.
What am I doing wrong?

TemplateBinding does not work within a DataTemplate.
You can use this workaroud:
<Window.Resources>
<BitmapImage x:Key="image_new_patient" UriSource="bsp.jpg" />
<local:ImageConverter x:Key="imageConverter" />
<Style x:Key="DatabaseButtonWithImageTag" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Width="100" Source="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Tag}" />
<ContentControl Grid.Column="1" Content="{TemplateBinding Content}" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<Image Source="{StaticResource image_new_patient}" Width="50"/>
<Button Style="{StaticResource DatabaseButtonWithImageTag}" Tag="{StaticResource image_new_patient}" Width="150" Height="100">
Test!
</Button>
</StackPanel>

Related

WPF ListboxItems with ItemContainerStyle become unselectable

I coded the following ListBoxItemStyle to be able to place multiple elements into the listboxitem:
<Style x:Key="lbWithButton" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{TemplateBinding Content}" Grid.Column="0"/>
<xctk:IntegerUpDown Minimum="0" Value="0" Maximum="1000" Grid.Column="1"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Unfortunately i cant select ListboxItems anymore.
This also happens with only the textblock inside the listboxitem.
Help would be appreciated!
You must use ItemTemplate instead of ItemContainerStyle:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Content}" Grid.Column="0"/>
<xctk:IntegerUpDown Minimum="0" Value="0" Maximum="1000" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Shadow under hovered ListBoxItem (and not under it's text)

I need shadow under ListBoxItem on MouseOver. Bottom code works but the whole listbox including the TextBlock's letters have a shadow:
<ListBox ItemContainerStyle="{StaticResource Style1}"
And the item Style:
<Style x:Key="Style1" TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter Property = "Effect" >
<Setter.Value>
<DropShadowEffect ShadowDepth="10" Direction="0" Opacity="1" BlurRadius="5" Color="Black"/>
</Setter.Value>
</Setter>
</Trigger>
Simplified DataTemplate:
<DataTemplate x:Key="TemplateSimple" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}" Grid.Column="0"/>
<TextBlock Text="{Binding FirstName}" Grid.Column="1"/>
<TextBlock Text="{Binding LastName}" Grid.Column="2"/>
Example is simplified.
I also tried adding to the DataTemplate:
<Rectangle Grid.Column="0" Fill="GreenYellow" Grid.ColumnSpan="3">
and assigning the shadow to it, but it would react only if TextBlocks are empty. Other ideas are appreciated.
EDIT:
As you can see it is not really a shadow but a blurry text. If it was a shadow, it would change much on changing shadow length:
See this post, How do I apply an effect to a Border but not to its contents in WPF?, which has some documentation on this "feature".
The easiest workaround in your case might be to give the Grid in your DataTemplate a background color:
<DataTemplate x:Key="TemplateSimple" >
<Grid Background="White" > ...
EDIT:
A more thorough approach would be to apply the DropShadowEffect to an element that lies beneath the text, but doesn't contain the text. For example, add a rectangle to your DataTemplate:
<DataTemplate x:Key="TemplateSimple" >
<Grid Margin="2" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Style="{StaticResource RectStyle1}"
Fill="Lime" Grid.ColumnSpan="3" />
<TextBlock Text="{Binding Title}" Grid.Column="0" />
<TextBlock Text="{Binding FirstName}" Grid.Column="1" />
<TextBlock Text="{Binding LastName}" Grid.Column="2" />
</Grid>
</DataTemplate>
..and instead of having the DropShadowEffect in Style1, put it in RectStyle1, but still triggered by IsMouseOver on the parent ListBoxItem:
<Style x:Key="RectStyle1" TargetType="Rectangle" >
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBoxItem},
Path=IsMouseOver,
Mode=OneWay}"
Value="True" >
<Setter Property="Effect" >
<Setter.Value>
<DropShadowEffect ShadowDepth="10" Direction="0"
Opacity="1" BlurRadius="5"
Color="Black" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>

Alternate background color in Listview XAML

I'm using a listView based on itemTemplate.
So i need in my template to alternate the background color :
- fist row: white
- second row:gray
- third row: white
- forth: gray
this is my template:
<DataTemplate x:Key="ItemFlight" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="#28AADB" Margin="2">
<Image Source="{Binding Path=IsArrival, Converter={StaticResource BooleanToImageDisplayConverter}}" Width="30" Height="30" VerticalAlignment="Center" Margin="5"/>
</Border>
<Grid Grid.Column="1" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="6*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding FlightName}" FontWeight="Bold" Grid.Column="0" Grid.Row="0" Margin="10" Style="{StaticResource MyTextBlockStyle}"/>
<TextBlock Text="{Binding ArrivalOrDepartDateTime, Converter={StaticResource DateTimeConverter}}" FontWeight="Bold" Grid.Column="0" Grid.Row="1" Margin="10" Style="{StaticResource MyTextBlockStyle}"/>
<TextBlock Text="{Binding Terminal, Converter={StaticResource StringUpperConverter}}" Grid.Column="1" Grid.Row="0" Margin="10" Visibility="{Binding Path=IsArrival,Converter={StaticResource BooleanToVisibilityReverseConverter}}" Style="{StaticResource MyTextBlockStyle}"/>
<TextBlock Text="{Binding CityInfo.Name}" Grid.Column="1" Grid.Row="0" Margin="10" Visibility="{Binding Path=IsArrival,Converter={StaticResource BooleanToVisibilityConverter}}" Style="{StaticResource MyTextBlockStyle}"/>
<TextBlock Text="{Binding DepartureTime}" Grid.Column="1" Grid.Row="1" Margin="10" Style="{StaticResource MyTextBlockStyle}"/>
<TextBlock Text="{Binding CityInfo.Name}" Grid.Column="2" Grid.Row="0" Margin="10" Style="{StaticResource MyTextBlockStyle}" Visibility="{Binding Path=IsArrival,Converter={StaticResource BooleanToVisibilityReverseConverter}}"/>
<TextBlock Text="{Binding Terminal, Converter={StaticResource StringUpperConverter}}" Visibility="{Binding Path=IsArrival,Converter={StaticResource BooleanToVisibilityConverter}}" Grid.Column="2" Grid.Row="0" Margin="10" Style="{StaticResource MyTextBlockStyle}"/>
<TextBlock Text="{Binding ArrivalTime}" Grid.Column="2" Grid.Row="1" Margin="10" Style="{StaticResource MyTextBlockStyle}"/>
<TextBlock Text="{Binding Status}" Grid.Column="3" Grid.Row="0" Grid.RowSpan="2" Margin="15" Style="{StaticResource MyTextBlockStyle}" Foreground="#EA6A1E" FontSize="20" TextWrapping="Wrap" />
</Grid>
</Grid>
</DataTemplate>
How Can I do this please??
I tried this and it works for me.
<Window x:Class="TryResponses.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:TryResponses"
xmlns:system="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<vm:MainWindowViewModel x:Key="MainWindowViewModel" />
</Window.Resources>
<Grid Background="LightGray" DataContext="{StaticResource MainWindowViewModel}">
<Grid.Resources>
<Style TargetType="ListViewItem">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightGray" />
</Trigger>
</Style.Triggers>
</Style>
<DataTemplate DataType="system:String">
<!-- put your data template here -->
</DataTemplate>
</Grid.Resources>
<ListView ItemsSource="{Binding Items}" AlternationCount="2" />
</Grid>
I hope this will help.
Regards
Claude
You should use AlternationCount property and it works on ListBox,ListView or any other control that inherits from ItemsControl.
The property definition and two examples are included at
https://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.alternationcount%28v=vs.110%29.aspx)
To view more clearly the selected lines, you can try this : (don't take care about the colors and final render, i've not spent the necessary time to make it sexy)
<Grid DataContext="{StaticResource MainWindowViewModel}">
<Grid.Resources>
<local:FalseToCollapsedConverter x:Key="FalseToCollapsedConverter" />
</Grid.Resources>
<ListView ItemsSource="{Binding Items}" AlternationCount="2" HorizontalContentAlignment="Stretch">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Grid x:Name="line">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentControl Content="{Binding .}" Margin="4" />
<TextBlock Grid.Column="1" Text="V" Margin="4" Visibility="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem, Mode=FindAncestor}, Converter={StaticResource FalseToCollapsedConverter}}" />
<Border Grid.ColumnSpan="2" Background="#5500FF00"
BorderBrush="Blue" BorderThickness="2"
Visibility="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem, Mode=FindAncestor}, Converter={StaticResource FalseToCollapsedConverter}}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter TargetName="line" Property="Background" Value="#CCCCFF" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter TargetName="line" Property="Background" Value="#CCFFCC" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
</ListView>
</Grid>

DataTrigger in ControlTemplate does not work

I am new here and hope my first question meets stack overflow's requirements. I have done some research so far but could not figure it out myself.
I create a UserControl (derived from an intermediate base Class) which should be able to change a color sign to a different color depending on its "VisualAlarmState" Property which is a DependencyProperty.
The Style plus ControlTemplate are rendered as expected but the DataTrigger at the end of the style does not change the color (=image) of VisualAlarmSign which is an Image element.
The code can be compiled and run without errors but the alarm state will not be shown as expected.
Something I do ot really understand either: I have to reference the Style dynamically because Style="{StaticResource DashboardItemStyle}" will be underlinded and at mouse hover says: "The resource "DashboardItemStyle" could not be resolved."
<ucbase:DashboardItemBase.Resources>
<BitmapImage x:Key="MO-Zylinderdeckel" UriSource="/ModuleDashboard;component/Resources/MO-Zylinderdeckel.tif" />
<BitmapImage x:Key="MO-Zylindermantel" UriSource="/ModuleDashboard;component/Resources/MO-Zylindermantel.tif" />
<BitmapImage x:Key="MO-Zylinderboden" UriSource="/ModuleDashboard;component/Resources/MO-Zylinderboden.tif" />
<BitmapImage x:Key="MO-Marker-Grün" UriSource="/ModuleDashboard;component/Resources/MO-Marker-Grün.tif" />
<BitmapImage x:Key="MO-Marker-Orange" UriSource="/ModuleDashboard;component/Resources/MO-Marker-Orange.tif" />
<BitmapImage x:Key="MO-Marker-Rot" UriSource="/ModuleDashboard;component/Resources/MO-Marker-Rot.tif" />
<Style x:Key="DashboardItemStyle" TargetType="{x:Type ucbase:DashboardItemBase}">
<Setter Property="Template" x:Name="Template1">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ucbase:DashboardItemBase}">
<dxlc:Tile x:Name="Tile" Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="0" Grid.RowSpan="1"
Height="128.5" Width="208.5" Background="{x:Null}">
<dxlc:Tile.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="11.5" />
<RowDefinition Height="*" />
<RowDefinition Height="12.5" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="6.5" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="0" Grid.RowSpan="1"
HorizontalAlignment="Stretch" Stretch="Fill" VerticalAlignment="Stretch"
Source="{StaticResource MO-Zylinderdeckel}" />
<Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Grid.RowSpan="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="6.5" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="1" Grid.RowSpan="2"
HorizontalAlignment="Stretch" Stretch="Fill" VerticalAlignment="Stretch"
Source="{StaticResource MO-Zylindermantel}" />
<Image x:Name="VisualAlarmSign" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Height="14"
Margin="0,20,0,0" Width="19.5" HorizontalAlignment="Right"
VerticalAlignment="Top" Source="{StaticResource MO-Marker-Grün}" />
</Grid>
<Image Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="3" Grid.RowSpan="1"
HorizontalAlignment="Stretch" Stretch="Fill" VerticalAlignment="Stretch"
Source="{StaticResource MO-Zylinderboden}" />
</Grid>
</dxlc:Tile.Content>
</dxlc:Tile>
<ControlTemplate.Triggers>
<!-- This Trigger has no effect. Why?-->
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=VisualAlarmState}">
<DataTrigger.Value>
<vmbase:AlarmState>Alarm</vmbase:AlarmState>
</DataTrigger.Value>
<Setter TargetName="VisualAlarmSign" Property="Source"
Value="{StaticResource MO-Marker-Rot}" />
</DataTrigger> </ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ucbase:DashboardItemBase.Resources>
Working Solution
I removed Source={StaticResource MO-Marker-Grün} from the <Image> element and I moved the <DataTrigger> from <ControlTemplate.Triggers> to <Style.Triggers> in <Image.Style> which resulted in the following XAML code:
<ucbase:DashboardItemBase.Resources>
...
<BitmapImage x:Key="MO-Marker-Rot" UriSource="/ModuleDashboard;component/Resources/MO-Marker-Rot.tif" />
...
<Style x:Key="DashboardItemStyle" TargetType="{x:Type ucbase:DashboardItemBase}">
<Setter Property="Template" x:Name="Template1">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ucbase:DashboardItemBase}">
<dxlc:Tile x:Name="Tile" Grid.Column="0" Grid.ColumnSpan="1" Grid.Row="0" Grid.RowSpan="1"
Height="128.5" Width="208.5" Background="{x:Null}">
<dxlc:Tile.Content>
<Grid>
...
<Image x:Name="VisualAlarmSign" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0"
Height="14" Margin="0,20,0,0" Width="19.5" HorizontalAlignment="Right"
VerticalAlignment="Top" >
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=VisualAlarmState}"
Value="Alarm">
<Setter Property="Image.Source"
Value="{StaticResource MO-Marker-Rot}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
...
</Grid>
</dxlc:Tile.Content>
</dxlc:Tile>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ucbase:DashboardItemBase.Resources>
Try setting the source of image using style property setter. Some how trigger behave wired.
<Image x:Name="VisualAlarmSign" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Height="14"
Margin="0,20,0,0" Width="19.5" HorizontalAlignment="Right"
VerticalAlignment="Top">
<Image.Style>
<Style>
<Setter TargetName="VisualAlarmSign" Property="Source"
Value="{StaticResource MO-Marker-Grün}" />
</Style>
</Image.Style>
</Image>
Make sure to remove the source property in the image tag.
Some how triggers may not set properties we have used in the tag. in your case you set the value of source in the image tag. if you set the same value through style setter it may worm. its worth a try.

Turning a grid into a button

I have a 2 column grid that I want to wrap with a <Button> now when I do that it totally screws the layout of the grid, how do I disable the style of the button so that the grid is clickable via the button but it looks the same.
When I start I have the following xaml
<Grid>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180*" />
<ColumnDefinition Width="296*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding image}" Margin="10,10,10,10"/>
<StackPanel Grid.Column="1">
<TextBlock Grid.Column="1" Text="{Binding hoursAgo}" FontSize="16" FontWeight="Light" FontStyle="Italic"></TextBlock>
<TextBlock FontSize="26.667" TextDecorations="Underline" Text="{Binding title}" TextWrapping="Wrap" Height="40" Width="295" HorizontalAlignment="Left" VerticalAlignment="Top" Foreground="#FF3253B8" Canvas.Top="22" Grid.Column="1" >News Title Goes here</TextBlock>
<TextBlock FontSize="21.333" Text="{Binding description}" TextWrapping="Wrap" d:LayoutOverrides="VerticalAlignment" Grid.Column="1" />
</StackPanel>
</Grid>
</Grid>
If I use expression blend to convert to a button it messes the source a bit, which is not what I want
<UserControl.Resources>
<Style x:Key="SelectedEntry" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180*" />
<ColumnDefinition Width="296*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding image}" Margin="10,10,10,10"/>
<StackPanel Grid.Column="1">
<TextBlock FontSize="26.667" TextDecorations="Underline" Text="{Binding title}" TextWrapping="Wrap" Height="40" Width="295" HorizontalAlignment="Left" VerticalAlignment="Top" Foreground="#FF3253B8" Canvas.Top="22" Grid.Column="1" ><Run Text="News Title Goes here"/></TextBlock>
<TextBlock FontSize="21.333" Text="{Binding description}" TextWrapping="Wrap" d:LayoutOverrides="VerticalAlignment" Grid.Column="1" />
</StackPanel>
</Grid>
<ContentPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="FontWeight" Value="Light"/>
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontStyle" Value="Italic"/>
</Style>
</UserControl.Resources>
<Button Content="{Binding hoursAgo}" Style="{StaticResource SelectedEntry}"/>
now the description is not showing in the grid.
Open Blend, right click the Grid that you want to turn into a Button and select Make Into Control.
Then in the popup window, select which control you want it to turn to, in your case, a Button. :) That's it.

Resources