Binding an image in a datatemplate - wpf

I'm trying to add a menu to my application, I'd like that my menu header is the currently connected user's picture.
My issue is that every binding works except the one for the image, from what I've understood on the net the DataTemplate I use to replace the menu header by a picture doesn't have access to it's parent Datacontext. I tried to use some stuff like relative source and other tricks but with no luck (certainely related to the fact that I'm new in mvvm and I obviously still have a lot to learn :) )
Here's the code I'm using :
<Grid DataContext="{Binding User}">
<DockPanel>
<Label Content="{Binding Strings.Hello, Source={StaticResource StringLocalizer} }" VerticalAlignment="Center" Padding="0,0,5,0" FontFamily="{DynamicResource Font_Normal}" FontSize="15" Foreground="White"/>
<TextBlock Text="{Binding DisplayName, TargetNullValue='Guest', FallbackValue='Guest'}" VerticalAlignment="Center" HorizontalAlignment="Left" FontFamily="{DynamicResource Font_Normal}" FontSize="15" Foreground="White"/>
<Menu Name="LogonMenu" Margin="10,0,0,0" DataContext="{Binding User}">
<MenuItem >
<MenuItem.HeaderTemplate>
<DataTemplate>
<!--<Image Source="{Binding Datacontext.Image,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Application}}, Converter={StaticResource ImageConverter}, FallbackValue={StaticResource DefaultUserIcon}}"/>-->
<Image DataContext="{Binding User}" Source="{Binding Path=Image, Converter={StaticResource ImageConverter}, FallbackValue={StaticResource DefaultUserIcon},Mode=TwoWay}"/>
</DataTemplate>
</MenuItem.HeaderTemplate>
<MenuItem Header="{Binding Strings.SignIn, Source={StaticResource StringLocalizer}}" Width="150" Margin="10,0,0,0" IsEnabled="{Binding Connected, Converter={StaticResource BoolInverterConverter}}" Visibility="{Binding RelativeSource={RelativeSource Mode=Self},Path=IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}" Command="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=DataContext.SignInCommand}"/>
<MenuItem Header="{Binding Strings.SignOut, Source={StaticResource StringLocalizer}}" Margin="10,0,0,0" IsEnabled="{Binding Connected}" Visibility="{Binding RelativeSource={RelativeSource Mode=Self},Path=IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}" Command="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=DataContext.SignOutCommand}"/>
<MenuItem Header="{Binding Strings.UserInformation, Source={StaticResource StringLocalizer}}" Margin="10,0,0,0" IsEnabled="{Binding Connected}" Visibility="{Binding RelativeSource={RelativeSource Mode=Self},Path=IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}"/>
</MenuItem>
</Menu>
</DockPanel>
</Grid>
In my case the image always shows the fallback picture, if someone could help me finding a way to have my user's picture it would be great.

Related

TemplateBinding as InvokeCommandAction CommandParameter not working?

I'm trying to write a reusable template for a control I want to use several times in my window. In it I have some commands with CommandParameter. The CommandParameter is an object I want to pass via the "Tag" property of this template.
For the "MenuItem" CommandParameter and the StackPanel "DataContext" this is working just fine. But for the "MouseDown" event (or "PreviewMouseDown", I tried both) via InvokeCommandAction I'm only getting a null as parameter. It is firing the command and calls the right method, but the parameter is always null.
Here my Xaml (shortend):
<Window.Resources>
<ControlTemplate x:Key="FavControl" TargetType="ContentControl">
<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu IsEnabled="{Binding FavContextMenuEnabled}">
<MenuItem Header="Bearbeiten"
Command="{Binding FavContextMenuEditCmd}"
CommandParameter="{TemplateBinding Tag}" />
<MenuItem Header="Löschen"
Command="{Binding FavContextMenuDeleteCmd}"
CommandParameter="{TemplateBinding Tag}" />
<Separator IsEnabled="{Binding UserisDev}" />
<MenuItem Header="Entwicklung"
Command="{Binding FavContextMenuStartDevCmd}"
CommandParameter="{TemplateBinding Tag}"
IsEnabled="{Binding UserisDev}" />
<MenuItem Header="Starte Objekt"
Command="{Binding FavContextMenuRunObjectCmd}"
CommandParameter="{TemplateBinding Tag}"
IsEnabled="{Binding UserisDev}" />
</ContextMenu>
</StackPanel.ContextMenu>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding FavoriteClickCmd}" CommandParameter="{TemplateBinding Tag}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<StackPanel Orientation="Vertical" DataContext="{TemplateBinding Tag}">
<Image Source="{Binding FavImage, UpdateSourceTrigger=PropertyChanged,Mode=OneWay}"
HorizontalAlignment="Center" VerticalAlignment="Center" Height="70" Width="70" />
<TextBlock Text="{Binding Description}" HorizontalAlignment="Center" />
</StackPanel>
</StackPanel>
</ControlTemplate>
</Window.Resources>
<!-- ... -->
<ContentControl Grid.Row="0" Grid.Column="0" Template="{StaticResource FavControl}" Tag="{Binding FavoriteArray[0]}" />
<ContentControl Grid.Row="0" Grid.Column="1" Template="{StaticResource FavControl}" Tag="{Binding FavoriteArray[1]}" />
<ContentControl Grid.Row="0" Grid.Column="2" Template="{StaticResource FavControl}" Tag="{Binding FavoriteArray[2]}" />
<!-- ... -->
I need this parameter in the code behind method to know which object to work with. So, how can I pass this object? Why is the TemplateBinding not working? Can anybody tell me, what I'm doing wrong?
P.S.: Sorry for errors, english is not my native language :)
Instead of TemplateBinding, use a RelativeSource binding to TemplatedParent.
<b:InvokeCommandAction Command="{Binding FavoriteClickCmd}"
CommandParameter="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}" />

How to bind to property of sibling control?

In a listbox of items, one item can be designated as the primary item. In the template, I have a button bound to a parameterized command (the specific item in the collection is the parameter passed to the command in the datacontext) that is visible only if the item is not currently the primary item. If the item IS the primary item, I want to display a static image. Since I can't bind the image to the command to witch I am binding the button, I figured I could bind the Visibility property of the image to the "inverse" of the Visibility property of the button. (i.e. when the button is visible, the image is hidden and vice versa.) But I can't figure out how to do this. The button is a sibling of the image within a grid within the template. Here's my template...
<DataTemplate>
<StackPanel Orientation="Vertical">
<Grid>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=FormattedNumber}" Style="{StaticResource FieldDataTextBlock}" FontWeight="Bold" />
<!-- How can I make this image aware of the following button's state? -->
<Image Grid.Column="2" Source="/Resources/Star.Pressed.png" Visibility="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path={}}" Width="20" Height="20" />
<Button Grid.Column="2" x:Name="btnMakePrimary" Style="{StaticResource StarButton}" Command="{Binding ElementName=lstPhoneNumbers, Path=DataContext.MakePrimaryPhoneNumberCommand}" CommandParameter="{Binding}" ToolTip="Set as display number." Visibility="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}, Converter={StaticResource BoolVisibility}}" />
<Button Grid.Column="4" Style="{StaticResource DetailsButton}" Command="{Binding ElementName=lstPhoneNumbers, Path=DataContext.ViewPhoneNumberCommand}" CommandParameter="{Binding}" />
<Button Grid.Column="6" Style="{StaticResource DeleteButton}" Command="{Binding ElementName=lstPhoneNumbers, Path=DataContext.DeletePhoneNumberCommand}" CommandParameter="{Binding}" />
</Grid>
<Grid >
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=PhoneTypeString}" Style="{StaticResource FieldDataTextBlock}" />
<TextBlock Grid.Column="2" Text="(notes)" Foreground="Blue" ToolTip="{Binding Path=PhoneNumberNote}" Visibility="{Binding Path=HasNote, Converter={StaticResource BoolVisibility}}" />
</Grid>
</StackPanel>
</DataTemplate>
Either that, or is there a way to bind the image to a method in the parent datacontext that takes a parameter?
Thanks.
J
Never mind... I was able to make it happen via the ElementName attribute of the binding and fixing an issue with the included image resource which was messing with my visuals:
<Button Grid.Column="2" Name="btnMakePrimary" Style="{StaticResource StarButton}" Command="{Binding ElementName=lstPhoneNumbers, Path=DataContext.MakePrimaryPhoneNumberCommand}" CommandParameter="{Binding}" ToolTip="Set as display number." Visibility="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}, Converter={StaticResource BoolVisibility}}" />
<Image Grid.Column="2" Source="/Resources/Star.Pressed.png" Visibility="{Binding ElementName=btnMakePrimary, Path=IsEnabled, Converter={StaticResource BoolVisibilityReverse}}" Width="20" Height="20" />

WPF Mouse binding in ListBox

I have this code , and i want to add Mouse Left click bindding .
I've done it like this , but for some reason seams that it have on effect.
<ListBox Grid.Row="5" Grid.Column="2" IsEnabled="{Binding UserGroupUpdatePermission}" ItemsSource="{Binding UserGroupTypeList }" HorizontalAlignment="Left" VerticalAlignment="Center" VerticalContentAlignment="Center" Width="300" Height="auto">
<ListBox.InputBindings>
<MouseBinding Command="{Binding Path = SaveCommand }" Gesture="LeftClick" />
</ListBox.InputBindings>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding Checked, Mode=TwoWay}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
am i doing some thing wrong ? is there any outher way for doing it ?

Can I use a DataTemplate for toolbar buttons and still make the name meaningful?

I have a Toolbar whose ItemSource is a collection of toolbarItems which contain the bitmap text and other info for the button and the xaml includes a DataTemplate to bind the data to the button.
Our app now needs to become 508 compliant and when I run the Accessible Event Watcher it is listing all the toolbar button names as "Unknown".
Can someone tell me how to provide a meaningful name to the buttons?
Here's the portion of xaml applying to this issue:
<ToolBar.ItemTemplate>
<DataTemplate DataType="{x:Type src:toolBarItem}">
<DataTemplate.Resources>
<src:toolBarItemConverter x:Key="buttonConverter" />
<src:booleanToVisibilityConverter x:Key="boolToVisibilityConverter" />
<src:toolBarButtonFormatConverter x:Key="toolBarFormatDisplayConverter" />
<src:stringToVisibilityConverter x:Key="stringToVisibilityDisplayConverter" />
</DataTemplate.Resources>
<StackPanel Orientation="Horizontal">
<Border Style="{StaticResource SeparatorStyle}" Visibility="{Binding menuSeparator, Converter={StaticResource boolToVisibilityConverter}}"/>
<Button x:Name="listButton" Height="{Binding menuHeight, Mode=OneWay}" Width="{Binding menuWidth}" VerticalAlignment="Top" HorizontalAlignment="Center" Visibility="{Binding isActiveButton, Converter={StaticResource boolToVisibilityConverter}}" Tag="{Binding}"
ToolTip="{Binding menuTooltip}" IsEnabled="{Binding isEnabled}" >
<UniformGrid VerticalAlignment="Center" HorizontalAlignment="Center" Rows="{Binding menuText,Converter={StaticResource toolBarFormatDisplayConverter}}" >
<!-- button image -->
<Image Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding menuImage, Converter={StaticResource buttonConverter}}"/>
<!-- button name -->
<Viewbox StretchDirection="DownOnly" HorizontalAlignment="Center" VerticalAlignment="Bottom" Visibility="{Binding menuText, Converter={StaticResource stringToVisibilityDisplayConverter}}" >
<TextBlock x:Name="buttonName" FontFamily="Segoe UI" Width="{Binding menuWidth}" FontSize="12" Grid.Row="1" TextAlignment="Center" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Bottom" Text="{Binding menuText}" Foreground="Black" />
</Viewbox>
</UniformGrid>
<!-- </StackPanel> -->
</Button>
</StackPanel>
</DataTemplate>
</ToolBar.ItemTemplate>
Thanks,
Ron
OK we figured this out. Need to simply bind your names to the AutomationProperties.Name
<Button x:Name="listButton" AutomationProperties.Name="{Binding menuText}"
Height="{Binding menuHeight, Mode=OneWay}" Width="{Binding menuWidth}"
VerticalAlignment="Top" HorizontalAlignment="Center"
Visibility="{Binding isActiveButton,
Converter={StaticResource boolToVisibilityConverter}}"
Tag="{Binding}" ToolTip="{Binding menuTooltip}" IsEnabled="{Binding isEnabled}" >

WPF MenuItem Header and HeaderTemplate

I want to bind a list of KeyValuePair to a list of MenuItems.
I thought I should use MenuIten.HeaderTemplate, but it didn't work. I only got blank headers.
<MenuItem
Header="Template"
ItemsSource="{Binding Path=Samples}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem>
<MenuItem.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Key}" FontWeight="Bold"/>
<TextBlock Text="{Binding Path=Value}" FontStyle="Italic" Margin="5,0,0,0"/>
</StackPanel>
</DataTemplate>
</MenuItem.HeaderTemplate> </MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
Then I replaced MenuItem.HeaderTemplate with MenuItem.Header, it worked.
<MenuItem
Header="Template"
ItemsSource="{Binding Path=Samples}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem>
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Key}" FontWeight="Bold"/>
<TextBlock Text="{Binding Path=Value}" FontStyle="Italic" Margin="2,0,0,0"/>
</StackPanel>
</MenuItem.Header>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
Can anyone explain to me why HeaderTemplate doesn't work here?
Micah is correct. In the first approach I told the menu item how to template itself but never told it what data it binds to! The following works:
<MenuItem
Header="Template"
ItemsSource="{Binding Path=Samples}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding}">
<MenuItem.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Key}" FontWeight="Bold"/>
<TextBlock Text="{Binding Path=Value}" FontStyle="Italic" Margin="5,0,0,0"/>
</StackPanel>
</DataTemplate>
</MenuItem.HeaderTemplate>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
Because the HeaderTemplate doesn't have access to the data being bound to the menu item.
The purpose of the Template is to add some elements to the VisualTree. DataTemplate is used for the sub-items ([Sub]MenuItem, ListBoxItem in ListBox, and so on) and is applied to the items holder, it is contrary to the ControlTemplate, wich is applied to the control itself.
What you actually did by this
<MenuItem
Header="Template"
ItemsSource="{Binding Path=Samples}">
<MenuItem.ItemTemplate>
<DataTemplate>
....
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
is telling "I want take MenuItem content and Insert the data, wich must be visualized". And then insert this insted dots:
<MenuItem Header="{Binding}">... </MenuItem>
So you are inserting additional menu item to the currently iterating menu item. I can't see the point.
Next is more clear:
<MenuItem Header="Template" ItemsSource="{Binding Samples}">
<MenuItem.Resources>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding SomeCommand}" />
</Style>
</MenuItem.Resources>
<MenuItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
The HeaderTemplate definition should be a DataTemplate, not direct UI content :
...
<MenuItem.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Key}" FontWeight="Bold"/>
<TextBlock Text="{Binding Path=Value}" FontStyle="Italic" Margin="2,0,0,0"/>
</StackPanel>
</DataTemplate>
</MenuItem.HeaderTemplate>
...

Resources