Image in first tab header in wpf TabHeader - wpf

I want to display an image in a first tab header of a TabControl in a currently fully working Prism MVVM WPF application.
Complete description as follows:
When the user select an item from the Category list in the left region it displays “More Details” and “Related Products” on the right region. This right region contains a TabControl inside a UserControl.
First Tab shows “More category Details” while second tab shows “Related Products”. Data is shown correctly. Now I want to display category thumbnail and the Category name in First tab header only.
I tried Using a HeaderTemplate on the First tab as follows
<TabControl VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" >
<TabItem Name="tabItemCategoryMoreInfo" >
<TabItem.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image x:Name="viewImage" Height="20" Width="20" Margin="0,0,2,0"
Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl} }, Path=Content.DataContext.SelectedParent.PictureBinary}"/>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem} }, Path=Content.DataContext.SelectedParent.CategoryName}"
VerticalAlignment="Center" FontSize="14" FontWeight="SemiBold" />
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem} }, Path=Content.DataContext.SelectedParent.PictureBinary}" Value="{x:Null}" >
<Setter TargetName="viewImage" Property="Source" Value="/CatalogModule;component/Images/ItemIcon.png" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</TabItem.HeaderTemplate>
<ContentControl prism:RegionManager.RegionName="CategoryMoreDetailsRegion" />
</TabItem>
<TabItem Header="Products" Name="tabItemCategoryProducts">
<ContentControl prism:RegionManager.RegionName="CategoryProductsRegion" />
</TabItem>
It didn’t show the product name or the product image. But it show only default image, so the Triggers looks working. Can some please help?
EDIT:
Initially I used the TabItem instead of TabControl in the image data path:
<Image x:Name="viewImage" Height="20" Width="20" Margin="0,0,2,0"
Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem} }, Path=Content.DataContext.SelectedParent.PictureBinary}"/>

The Paths in your DataTemplate Bindings are different... that may explain why it doesn't work. If I understand you correctly, you say that the Binding Path in the DataTrigger works, so perhaps changing your Binding Path for the ImageSource and TextBlock.Text properties might work?:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image x:Name="viewImage" Height="20" Width="20" Margin="0,0,2,0"
Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}, Path=Content.DataContext.SelectedParent.PictureBinary}"/>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Content.DataContext.SelectedParent.CategoryName}"
VerticalAlignment="Center" FontSize="14" FontWeight="SemiBold" />
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Content.DataContext.SelectedParent.PictureBinary}" Value="{x:Null}" >
<Setter TargetName="viewImage" Property="Source" Value="/CatalogModule;component/Images/ItemIcon.png" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Just in case you can't see the difference, you were using this in your Image.Source Binding.Path:
AncestorType={x:Type TabControl}

Related

How to add CheckBox content from resource file in wpf?

I have a combobox in which first item is checkbox to select all entries from below drop down list. With hard coded string its working fine but now I want to localize it...want to set string from resource file but as its deeply inserted couldn't add it. For that I tried adding panel and one checkbox along with textblock also simply separated textblock from checkbox.
This is code :
<ComboBox Name="CmbEntries" IsTabStop="{Binding CurrentDialogViewModel, Converter={StaticResource NullToBoolConverter}}" Grid.Column="1" Grid.Row="4" VerticalAlignment="Top" Margin="2,0,0,5" SelectedItem="{Binding SelectedEntries}" SelectedIndex="0" HorizontalAlignment="Left" Width="400">
<ComboBox.Resources>
<CollectionViewSource x:Key="EntriesCollection" Source="{Binding DicomDir.Entries}"/>
</ComboBox.Resources>
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem>
<CheckBox x:Name="all" Margin="8,0,0,0"
IsChecked="{Binding IsAllEntriessSelected, Mode=TwoWay}"
Command="{Binding SelectAllEntriessCommand}"
CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}"
**Content="Select All Entries"** />
</ComboBoxItem>
<CollectionContainer Collection="{Binding Source={StaticResource EntriesCollection}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Margin="8,0,0,0"
IsChecked="{ Binding Path=IsAnyEntitySelected, Mode=TwoWay }"
Command="{Binding SelectAllEntityCommand}"
CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}" />
<TextBlock Margin="5,0,0,0" TextWrapping="Wrap" Text="{Binding DisplayEntriesInfo}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding HasSelectedEntities}" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
Scrshot1-Expected
Scrshot2-Actual with Resx
In this case, is it possible to read it directly from resource file?
To bind the content to a resource you do:
<Window ...
xmlns:properties="clr-namespace:YourNamespace.Properties">
<Grid>
<CheckBox Content="{x:Static properties:Resources.Foo}" />
</Grid>
</Window>
For this to work you need Resources to be public.
If it is not you get:
Provide value on 'System.Windows.Markup.StaticExtension' threw an exception...
StaticExtension value cannot be resolved to an enumeration, static field, or static property.

How to make a ToolTip not bigger than it's Control?

I have a Xceed DataGrid, and in one of the Columns there is a text that can be very long. I want to show just part of the text, and if the user hovers the mouse on top of it, a Tooltip will show the entire text.
I am trying to set the ToolTip's MaxWidh like this:
<DataTemplate x:Key="TooltipTextBlockTemplate">
<TextBlock Text="{Binding}" x:Name="DataTextBlock">
<TextBlock.ToolTip>
<TextBlock Text="{Binding}" TextWrapping="Wrap" MaxWidth="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type xcdg:Column}}}" />
</TextBlock.ToolTip>
</TextBlock>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="">
<Setter TargetName="DataTextBlock" Property="ToolTipService.IsEnabled" Value="False" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
I have tried AncestorType={x:Type xcdg:Column}}}" and AncestorType={x:Type TextBlock}}}" but it just expands to the whole screen.

Adding image to radiobutton that can act as Toggle button using wpf

I want to use 2 radiobuttons like a toggle button using WPF. I tried something like this:
<RadioButton Name="RightAnswer" Width="20">
<RadioButton.Template>
<ControlTemplate>
<ToggleButton IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<Image Width="20"
Height="20"
VerticalAlignment="Center"
Source="{Binding Content,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}"
ToolTip="Right Answer" />
</ToggleButton>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
<RadioButton Name="WrongAnswer" Width="20">
<RadioButton.Template>
<ControlTemplate>
<ToggleButton IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<Image Width="20"
Height="20"
VerticalAlignment="Center"
Source="{Binding Content,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}"
ToolTip="Wrong Answer" />
</ToggleButton>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
I could make this work but it shows blank buttons. I want to have buttons with Image in each of them and on checked i should bind it with ViewModel code.
Update: I added Images in each of them which now works well. I hoping to connect the press events to VM property.

Wpf Treeview Contextmenu DataContext

I am trying to set the Datacontext of my Contextmenu - but my Code does not work. Very similar code works at another location, so I would be grateful if somebody could explain why it does not work.
My Treeview looks like this:
Beware: it is rather long, but I think the nested structure is part of the problem, so I do want to shrink it.
The Problem occurs on the second "level" at the ppChart Binding.
<TreeView x:Name ="Presentation_SlidesWithIndex" Grid.ColumnSpan="1" HorizontalAlignment="stretch" Height="auto" Margin="0,0,3,0" VerticalAlignment="stretch" Width="auto" Tag="{Binding DataContext, ElementName=LayoutRoot}">
<TreeView.ItemContainerStyle>
<!--expand Charts when they contain elements-->
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding HasCharts}"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type pp:PPSlide}" ItemsSource="{Binding Charts}">
<StackPanel x:Name="PPSlideElements" Orientation="Horizontal">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<!--Trigger for Slides with Charts-->
<DataTrigger Binding="{Binding Path=HasCharts}" Value="True" >
<Setter Property="Background" Value="LightBlue" />
</DataTrigger>
<!--Trigger for Slides with NO Charts-->
<DataTrigger Binding="{Binding Path=HasCharts}" Value="False" >
<Setter Property="Opacity" Value=".5" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBlock FontSize="15">
<Run Text="Slide "></Run>
<Run Text="{Binding Path=Index}"></Run>
</TextBlock>
<!--<Image Source="/Images/pptIcon.png" Height="10"></Image>-->
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type pp:PPChart}" ItemsSource="{Binding ExcelSource}">
<StackPanel x:Name="PpChartElements" Orientation="Horizontal" AllowDrop="True" cal:Message.Attach="[Event Drop] = [Action DropItem($eventArgs,$view)]" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=UserControl}}">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<!--Trigger for Charts with DataSource set-->
<DataTrigger Binding="{Binding Path=HasDataSourceSet}" Value="True" >
<Setter Property="Background" Value="LightGreen" />
</DataTrigger>
<!--Trigger for Charts with DataSource nit set-->
<DataTrigger Binding="{Binding Path=HasDataSourceSet}" Value="False" >
<Setter Property="Background" Value="Orange" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<Image Source="{Binding ChartType, Converter={StaticResource PowerPointChartTypeConverter}}" Width="19" Height="19" Margin="2,2,4,2"></Image>
<TextBlock FontSize="14" Text="{Binding Path=ShapeName}" VerticalAlignment="Center">
<TextBlock.ContextMenu>
<ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag.AddEntityCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
<MenuItem Header="Löse Verknüpfung" cal:Message.Attach="DeleteLink($datacontext)" ToolTip="Löscht einen bestehenden Link zu einer Excel Datei"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
<Image Source="{Binding PowerPointWriteStatus, Converter={StaticResource PowerPointWriteStatusConverter}}" Width="19" Height="19" Margin="2,2,4,2" ToolTip="Zeigt erfolg oder misserfolg des Erstellens an"></Image>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type pp:PPSourceExcelLink}">
<StackPanel x:Name="PpSourceExcelLinkStackPanel" Orientation="Vertical">
<TextBlock FontSize="14">
<Run Text="Datei: "></Run>
<Run Text="{Binding Path=ExcelFileName, Mode=OneWay}"></Run>
</TextBlock>
<TextBlock FontSize="14">
<Run Text="Tabelle: "></Run>
<Run Text="{Binding Path=SourceTableID}"></Run>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
I think your problem lies exactly in this line of code:
cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag.AddEntityCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
To fix it you need to change this to:
cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag.AddEntityCommand, RelativeSource={RelativeSource Self}}"
but this alone won't fix your problem because the target of the action message will be the TextBlock which doesn't have its Tag property set.
Anyway you should end up with code similar to this:
<TextBlock FontSize="14" Text="{Binding Path=ShapeName}" VerticalAlignment="Center" Tag="{Binding DataContext, RelativeSource={RelativeSource Self}}">
<TextBlock.ContextMenu>
<ContextMenu cal:Action.TargetWithoutContext="{Binding RelativeSource={RelativeSource Self},Path=PlacementTarget.Tag}">
<MenuItem Header="Löse Verknüpfung" cal:Message.Attach="DeleteLink($datacontext)" ToolTip="Löscht einen bestehenden Link zu einer Excel Datei" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
I answered a similar question recently and you can take a look at for more details.
I found a Solution which works fairly well - but why it works is beyond me:
<TextBlock FontSize="14" Text="{Binding Path=ShapeName}" VerticalAlignment="Center" Tag="{Binding DataContext, RelativeSource={AncestorType=TreeView}}">
<TextBlock.ContextMenu>
<ContextMenu cal:Action.TargetWithoutContext="{Binding RelativeSource={RelativeSource Self},Path=PlacementTarget.Tag}">
<MenuItem Header="Löse Verknüpfung" cal:Message.Attach="DeleteLink($datacontext)" ToolTip="Löscht einen bestehenden Link zu einer Excel Datei" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
Note how the Ancestertype treeview is used. my bet guess is that it walks the Visual tree until it finds the Treeview, which has the proper DataContect.
Thanks to Sniffer, which did a very good job !
As stated in RelativeSource binding from a ToolTip or ContextMenu there is no need to add the tag to the PlacementTarget. This makes it shorter, as there is no need to add a tag to the control and to the binding path of the ContextMenu, e.g.:
<TextBlock FontSize="14" Text="{Binding Path=ShapeName}" VerticalAlignment="Center">
<TextBlock.ContextMenu>
<ContextMenu cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Löse Verknüpfung" cal:Message.Attach="DeleteLink($datacontext)" ToolTip="Löscht einen bestehenden Link zu einer Excel Datei" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
and in the ViewModel
public void DeleteLink(object parameter)
{
if (parameter == null)
return;
var param = parameter as YourDataContextType;
if (! (param is YourDataContextType))
return;
// your delete handling
}

Conditional formatting for the Header content

I have the following template for some header:
<telerik:RadExpander.Header>
<StackPanel Orientation="Horizontal" DataContext="{Binding CurrentItem, ElementName=activityProductGrid}">
<TextBlock Text="{Binding Strings[Product], Source={StaticResource LanguageResources}, StringFormat='{}{0}: '}" />
<TextBlock Text="{Binding Product.Name}" FontWeight="Bold" />
<TextBlock Text="{Binding Strings[GroupName], Source={StaticResource LanguageResources}, StringFormat=', {0}: '}" />
<TextBlock Text="{Binding GroupName}" />
<TextBlock Text="{Binding Strings[UnitPrice], Source={StaticResource LanguageResources}, StringFormat=', {0}: '}" />
<TextBlock Text="{Binding UnitPrice}" />
</StackPanel>
</telerik:RadExpander.Header>
How can I do conditional formmatting of the header, if for example Product == null, then Header should not display anything?
Edit: This one works.
<StackPanel Orientation="Horizontal" DataContext="{Binding CurrentItem, ElementName=activityProductGrid}">
<i:Interaction.Triggers>
<ie:DataTrigger Binding="{Binding}" Value="{x:Null}">
<ie:ChangePropertyAction TargetObject="{RelativeSource={RelativeSource AncestorType=StackPanel}}" PropertyName="Visibility">
<ie:ChangePropertyAction.Value>
<Visibility>Collapsed</Visibility>
</ie:ChangePropertyAction.Value>
</ie:ChangePropertyAction>
</ie:DataTrigger>
</i:Interaction.Triggers>
<-- from this point the came code as above -->
</StackPanel>
Specifically for null, you can specify binding parameters for a replacement value, or one to display in case of binding errors:
<TextBlock
Text="{Binding Product.Name, TargetNullValue=(empty), FallbackValue=(error)}"/>
(Taken from the WPF Binding Cheatsheet)
EDIT: I noticed that you didn't just want a specific binding to have a different value, but the whole control to not be displayed. For this, you can use Styles and Triggers, binging a DataTrigger to your Product property, and setting Visibility if it's null.
<telerik:RadExpander.Header>
<StackPanel>
<StackPanel.Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding Product}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>
</telerik:RadExpander.Header>

Resources