Icon DataTemplate for Icon MenuItem - wpf

I create some graphics for menuitem.icon.
<DataTemplate x:Key="navigation_arrow">
<DockPanel LastChildFill="True" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<Canvas>
<Rectangle Fill="Red" Width="30" Height="20"/>
</Canvas>
</Grid>
</DockPanel>
</DataTemplate>
And then I try use this template for menuitem.icon
<MenuItem Header="" Icon="{Binding navigation_arrow}"/>
But it is empty menuitem. If I insert template code in MenuItem.Icon all work good

First: your binding is wrong. You must use this key as {DynamicResource navigation_arrow} or {StaticResource navigation_arrow}.
But It's not working. Your icon will be "System.Windows.DataTemplate" string, in this case.
DataTemplate means "It will apply a template for a data". You haven't got Data for Icon, so it cannot apply template for this.
You have to add concrete item as icon (like you mentioned) or create a style for it:
<Style TargetType="MenuItem">
<Setter Property="Icon">
<Setter.Value>
<DockPanel LastChildFill="True" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<Canvas>
<Rectangle Fill="Red" Width="30" Height="20"/>
</Canvas>
</Grid>
</DockPanel>
</Setter.Value>
</Setter>
</Style>
but the fancy way is:
use DrawingBrush from resource

You can use a ContentControl:
<MenuItem.Icon>
<ContentControl ContentTemplate="{StaticResource navigation_arrow}"/>
</MenuItem.Icon>

Related

Wpf change the background colour of an expander's header only

I have looked at many questions/answers but couldn't find what I was exactly looking for,
I am trying to change the background colour of the expander's header only and not have the same colour continue for the content within the expander. Preferably within xaml but a vb.net solution would suffice.
(Any comments or suggestions will be helpful)
If this is a duplicated question please direct me to the answer and leave the question open to help others avoid the same issue in the future!
Thanks.
I am not sure whether this is what you are exactly looking for, but you could change the header background by simply doing that:
<Expander VerticalAlignment="Center">
<Expander.Header>
<Grid Background="LightBlue">
<TextBlock Text="Expander Header"/>
</Grid>
</Expander.Header>
<StackPanel>
<TextBlock Text="Cotent"></TextBlock>
</StackPanel>
</Expander>
Or you could override the default Expander's Header DataTemplate by using HeaderTemplate
<Window.Resources>
<DataTemplate x:Key="HeaderText">
<Border Height="25" Background="LightBlue">
<TextBlock Text="{Binding}"
Margin="4 0"
VerticalAlignment="Center"
Foreground="White"
FontSize="11"
FontWeight="Normal"
/>
</Border>
</DataTemplate>
<Style TargetType="{x:Type Expander}">
<Setter Property="HeaderTemplate" Value="{StaticResource HeaderText}"/>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<Expander VerticalAlignment="Center" Header="Expander Header">
<StackPanel>
<TextBlock Text="Cotent"></TextBlock>
</StackPanel>
</Expander>
</Grid>
I had a lot of problems with getting the header background set.
I found the easiets weay to do it was to simply make a coloured rectangle and put it behind the expander. (use Margin and Height to make it fit)
<Rectangle Grid.Row="1" Grid.Column="0" Fill="LightBlue" Height="33" Margin="0,0,0,-35" />
or use a border if you want rounded corners:
<Border CornerRadius="15" Height="33" Margin="0,0,0,-35" Background="LightBlue" />

Tabitem header image

When I set image as Header of TabItem it looks like image in some gray area. How remove this surrouding area?
<TabControl TabStripPlacement="Left"
HorizontalContentAlignment="Left"
VerticalContentAlignment="Top">
<TabItem ToolTip="Элементы, в которых найдены несоответствия" Height="200"
Style="{StaticResource TabItemHeaderImageStyle}">
<TabItem.Header>
<Image Source="{StaticResource CheckImage}"
Margin="0"
Height="25" Width="25" />
</TabItem.Header>
<ListBox ItemsSource="{Binding unmatched.vs}"
MaxHeight="200"
ItemTemplate="{StaticResource VertexPresenterNotConformTemplate}" />
</TabItem>
<TabItem ToolTip="Элементы, соответствующие шаблону"
Style="{StaticResource TabItemHeaderImageStyle}">
<TabItem.Header>
<Image Source="{StaticResource UncheckImage}"
Height="25" Width="25" />
</TabItem.Header>
<ListBox ItemsSource="{Binding unmatched.vs}"
MaxHeight="200"
ItemTemplate="{StaticResource VertexPresenterConformTemplate}" />
</TabItem>
<Style x:Key="TabItemHeaderImageStyle" TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border"
Margin="0,0,-4,0"
BorderThickness="1,1,1,1"
CornerRadius="2,12,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"
RecognizesAccessKey="True"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
What I wish(TabItem's headers under each other without a gray area around it):
TabItem probably has a border around it's header that's gray (thus making a shadow around an image). See this link for TabItem ControlTemplate.
I'd try fiddling with the controltemplate or use an app like WpfInspector to see what's wrong with the template and get correct values.

How to make overlay control above all other controls?

I need to make a control appear above all other controls, so it will partially overlay them.
If you are using a Canvas or Grid in your layout, give the control to be put on top a higher ZIndex.
From MSDN:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="ZIndex Sample">
<Canvas>
<Rectangle Canvas.ZIndex="3" Width="100" Height="100" Canvas.Top="100" Canvas.Left="100" Fill="blue"/>
<Rectangle Canvas.ZIndex="1" Width="100" Height="100" Canvas.Top="150" Canvas.Left="150" Fill="yellow"/>
<Rectangle Canvas.ZIndex="2" Width="100" Height="100" Canvas.Top="200" Canvas.Left="200" Fill="green"/>
<!-- Reverse the order to illustrate z-index property -->
<Rectangle Canvas.ZIndex="1" Width="100" Height="100" Canvas.Top="300" Canvas.Left="200" Fill="green"/>
<Rectangle Canvas.ZIndex="3" Width="100" Height="100" Canvas.Top="350" Canvas.Left="150" Fill="yellow"/>
<Rectangle Canvas.ZIndex="2" Width="100" Height="100" Canvas.Top="400" Canvas.Left="100" Fill="blue"/>
</Canvas>
</Page>
If you don't specify ZIndex, the children of a panel are rendered in the order they are specified (i.e. last one on top).
If you are looking to do something more complicated, you can look at how ChildWindow is implemented in Silverlight. It overlays a semitransparent background and popup over your entire RootVisual.
Robert Rossney has a good solution. Here's an alternative solution I've used in the past that separates out the "Overlay" from the rest of the content. This solution takes advantage of the attached property Panel.ZIndex to place the "Overlay" on top of everything else. You can either set the Visibility of the "Overlay" in code or use a DataTrigger.
<Grid x:Name="LayoutRoot">
<Grid x:Name="Overlay" Panel.ZIndex="1000" Visibility="Collapsed">
<Grid.Background>
<SolidColorBrush Color="Black" Opacity=".5"/>
</Grid.Background>
<!-- Add controls as needed -->
</Grid>
<!-- Use whatever layout you need -->
<ContentControl x:Name="MainContent" />
</Grid>
Controls in the same cell of a Grid are rendered back-to-front. So a simple way to put one control on top of another is to put it in the same cell.
Here's a useful example, which pops up a panel that disables everything in the view (i.e. the user control) with a busy message while a long-running task is executed (i.e. while the BusyMessage bound property isn't null):
<Grid>
<local:MyUserControl DataContext="{Binding}"/>
<Grid>
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Visibility"
Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding BusyMessage}"
Value="{x:Null}">
<Setter Property="Visibility"
Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Border HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="DarkGray"
Opacity=".7" />
<Border HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
Padding="20"
BorderBrush="Orange"
BorderThickness="4">
<TextBlock Text="{Binding BusyMessage}" />
</Border>
</Grid>
</Grid>
Put the control you want to bring to front at the end of your xaml code. I.e.
<Grid>
<TabControl ...>
</TabControl>
<Button Content="ALways on top of TabControl Button"/>
</Grid>
This is a common function of Adorners in WPF. Adorners typically appear above all other controls, but the other answers that mention z-order may fit your case better.
<Canvas Panel.ZIndex="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="570">
<!-- YOUR XAML CODE -->
</Canvas>

Template Binding in Control template

I have the following control template.
I wish to set the source property for the image control in the control
template using Template Binding.
But since this is a control template for button control and the button control doesn't
have source property, i can't use TemplateBinding in this case.
<ControlTemplate x:Key="BtnTemplate" TargetType="Button">
<Border CornerRadius="5" Margin="15" Cursor="Hand">
<StackPanel>
<Image Name="Img" Style="{StaticResource ImageStyle}" Source="temp.jpg" Height="100" Width="100" Margin="5"></Image>
<Label Content="{TemplateBinding Content}" Background="Transparent" Margin="2"></Label>
</StackPanel>
</Border>
</ControlTemplate>
Since i have to set different images for different instances of button, i can't hardcode the path as well.
Please let me know how to tackle this situation.
I'd suggest using dynamic resources, e.g. define the template as follows:
<ControlTemplate x:Key="buttonTemplate" TargetType="Button">
<Border CornerRadius="5" Margin="15" Cursor="Hand">
<StackPanel Orientation="Horizontal" Background="Yellow">
<Image Source="{DynamicResource ResourceKey=Img}" Height="100" Width="100" Margin="5"></Image>
<Label Content="{TemplateBinding Content}" Background="Transparent" Margin="2"></Label>
</StackPanel>
</Border>
</ControlTemplate>
And use it like this:
<Button Content="Button" Template="{StaticResource ResourceKey=buttonTemplate}">
<Button.Resources>
<ImageSource x:Key="Img">SomeUri.png/</ImageSource>
</Button.Resources>
</Button>
TemplateBinding is a lightweight "binding", it doesn't support some features of traditional Binding, such as automatically type conversion using the known type converters associated with the target property (such as converting the string URI into a BitmapSource instance).
The following code can work properly:
<Window x:Class="GridScroll.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2">
<Window.Resources>
<Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="5" Margin="15" Cursor="Hand" Background="Red">
<StackPanel Orientation="Horizontal" Background="White">
<Image Name="Img" Source="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}" Margin="5"></Image>
<Label Content="{TemplateBinding Content}" Margin="2"></Label>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel Orientation="Horizontal">
<Button Style="{StaticResource ButtonStyle}" Tag="a.jpeg" Content="a"/>
<Button Style="{StaticResource ButtonStyle}" Tag="b.png" Content="b"/>
</StackPanel>
You haven't really said how you expect consumers of your button to set the source. You could use the Button.Tag property, for example, and then bind to that in your template. Or you could define your own control:
public class ImageButton : Button
{
// add Source dependency property a la Image
}
And then the template:
<ControlTemplate TargetType="ImageButton">
<Border CornerRadius="5" Margin="15" Cursor="Hand">
<StackPanel>
<Image Name="Img" Style="{StaticResource ImageStyle}" Source="{TempateBinding Source}" Height="100" Width="100" Margin="5"></Image>
<Label Content="{TemplateBinding Content}" Background="Transparent" Margin="2"></Label>
</StackPanel>
</Border>
</ControlTemplate>
I'm not sure that I understood your problem very well but why don't you use ContentPresenter? It allows to move the code for your Image at the higher level.
<ControlTemplate x:Key="BtnTemplate" TargetType="Button">
...
<ContentPresenter/>
</ControlTemplate>
...
<Button Template="{StaticResource BtnTemplate}">
<Image .../>
</Button>

Borderless ImageButtons in WrapPanel

I am attempting to create a WrapPanel with seamless ImageButtons containing Artwork. I put together the following ContentTemplate in the hopes that it would provide the seamless look required; however a thin white-line remained around each of the buttons. Can anyone steer me in the right direction?
<Button.ContentTemplate>
<DataTemplate DataType="{x:Type local:ArtInfo}">
<Border Name="border" BorderThickness="0" BorderBrush="blue" Height="280" Width="250" Background="#262c40">
<StackPanel>
<Grid>
<Grid.Resources>
<local:MyConverter x:Key="MyConverter"></local:MyConverter>
<ObjectDataProvider x:Key="Properties.Settings" ObjectType="{x:Type lcl:Properties.Settings}" />
</Grid.Resources>
<Image Name="ArtImage" Margin="10,15,0,0" Height="195" Width="195" VerticalAlignment="Top" >
<Image.Source>
<Binding Path="ArtImage"/>
</Image.Source>
</Image>
</Grid>
<TextBlock Text="{Binding Path=ArtClass}" Margin="10,-17,0,0" FontSize="11" Foreground="white" />
<TextBlock Text="{Binding Path=Student}" Margin="10,0,0,0" FontSize="11" Foreground="white" />
<TextBlock Text="1998" Margin="10,0,0,0" FontSize="11" Foreground="white" />
</StackPanel>
</Border>
</DataTemplate>
</Button.ContentTemplate>
The ContentTemplate tells WPF how to display the content within the Button -- the Button chrome (such as the border and background) remains, and the templated content is displayed within and over that chrome.
You want to replace the entire appearance of the Button, border and all, rather than just customising how its content is displayed. To do this, you need to use the Template property instead. The value of Button.Template is a ControlTemplate rather than a DataTemplate. Within that ControlTemplate, you can use the ContentPresenter to display the "data-templated" content.
In your case, since your DataTemplate is doing all the work, you could get away with a raw ContentPresenter as your template:
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter />
</ControlTemplate>
</Button.Template>
However, if all your buttons are using the same background, you could move this into the ControlTemplate:
<Button.Template>
<ControlTemplate TargetType="Button">
<Border BorderBrush="Blue" ...>
<ContentPresenter />
</Border>
</ControlTemplate>
</Button.Template>
You could then remove the Border from the DataTemplate. This would really only matter if you were planning to reuse the same Button.Template with other content templates and wanted to keep the appearance of the Button consistent across different kinds of content.
create a usercontrol, put the botton & image in a grid.
<Grid>
<Image Source="icon.png" Panel.ZIndex="1" />
<Button
Panel.ZIndex="2"
FocusVisualStyle="{x:Null}"
Background="Transparent"/>
</Grid>

Resources