I'm writing my first XAML template (be nice, please) for a custom button, and I'm trying to make a common occurrence (button icons) more integral to the setup.
Currently my template is as follows:
<ControlTemplate TargetType="Button" x:Key="tButton">
<Grid>
<Border x:Name="Background" CornerRadius="2" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
<Grid Background="{TemplateBinding Background}">
<Rectangle x:Name="BackgroundGradient" >
</Rectangle>
</Grid>
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<!-- icon image -->
<Image Grid.Column="0" />
<ContentPresenter
Grid.Column="1"
x:Name="contentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}" />
</Grid>
<Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
<Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="#FF6DBDD1" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
</Grid>
</ControlTemplate>
So I'm all set up to have text and an image, and the text part even works, but what I'd really love (and have no idea how to do) is pass the icon into the button.
I was trying to figure out how to get a custom property (for a URI) on the button that could be set in styling, but it all sort of went right over my head (it was a lot to hold in there, when combined with learning this whole templating thing). Is that even a valid approach? Maybe some way I could have the template pick up any image it finds in the button contents and use it as indicated?
Essentially, is it possible to have a standardized way for all of my buttons to have an option to have an icon? It would be much nicer than the messy solution of having every button have an image and a textblock, each of which need their own context-sensitive styling.
Finally, I (unfortunately) only have access to the XAML. I can do just about anything I want with it, but this is a redesign of an existing panel, and I don't have access to the C# functional bits.
Implement a button with a property for the icon source
public class IconButton : Button
{
public static readonly DependencyProperty IconSourceProperty =
DependencyProperty.Register("IconSource", typeof(string), typeof(IconButton), new PropertyMetadata(default(string)));
public string IconSource
{
get { return (string)GetValue(IconSourceProperty); }
set { SetValue(IconSourceProperty, value); }
}
}
Adjust your template to fit that button and bind the image source to your custom property
<ControlTemplate TargetType="{x:Type local:IconButton}" x:Key="tbutton">
<Grid>
<Border x:Name="Background" CornerRadius="2" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
<Grid Background="{TemplateBinding Background}">
<Rectangle x:Name="BackgroundGradient" >
</Rectangle>
</Grid>
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<!-- icon image -->
<Image Grid.Column="0" Source="{TemplateBinding IconSource}"/>
<ContentPresenter
Grid.Column="1"
x:Name="contentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}" />
</Grid>
<Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
<Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="#FF6DBDD1" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
</Grid>
And simple use it
<local:IconButton IconSource="Resources\1.jpg" Template="{StaticResource tbutton}"></local:IconButton>
In addion to Omribitan :
CS:
public class IconButton : Button
{
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(string), typeof(IconButton), new PropertyMetadata(null));
public string ImageSource
{
get { return (string)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
}
xaml :
<ControlTemplate TargetType="Button" x:Key="tButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- icon image -->
<Image x:Name=img ImageSource="{TemplateBinding ImageSource}" />
<ContentPresenter Grid.Column="1" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ImageSource" Value="{x:Null}">
<Setter TargetName=img Property=Visibility Value=Collapesd/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Related
I have a button in XAML which i styled the way I need it. This is XAML code of that button:
<Button x:Name="btnAddNewItem"
Grid.Column="0" Grid.Row="0"
FontSize="15"
BorderThickness="1.5"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Foreground="White"
Background="White"
BorderBrush="#0091EA" Margin="5,0,0,0" Height="90" Width="90">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Button.Template>
And I would like to achieve something like this, so I would like to delete xaml button, and create same button programatically when its needed, with same style and everything like I did in xaml, example how I would like to create it:
private void AddSubmenuButton(string name)
{
MyButton button = new MyButton();
button.ButtonText = name;
}
Is this possible and if so: how?
P.S I tried classic way, like this:
Button a = new Button();
a.BorderThickness = new Thickness(1);
a.Foreground = new SolidColorBrush(Colors.Black);
a.BorderBrush = mySolidColorBrush;
a.Content = "Button1";
a.Width = 90;
a.Height = 90;
But I get this:
It's possible to notice that thickness it not 1 at all, it has some weird value
and I don't know how to change it.. So that is reason why I created button in xaml which looks much more nice and I want to call it/create it from code behind.
EDIT:
#mm8 THANK YOU A LOT!
THAT'S IT!
This is awesome mate, but what about that If I would like to place icon + text in my button, I would ussualy
add something like this and its fine for me:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80*">
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Image Source="/MyProject.Wpf;component/Icons/customer-icon.png" Margin="10" Grid.Row="0" Width="Auto"/>
<TextBlock Foreground="Black" Margin="0,0,0,3" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" >Izlaz</TextBlock>
</Grid>
as you can see I would add Grid to my button and it would look like this:
<Button x:Name="btnAddNewItem"
Grid.Column="0" Grid.Row="0"
FontSize="15"
ToolTip="Podaci"
BorderThickness="1.5"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Foreground="White"
Background="White"
BorderBrush="#0091EA" Margin="5,0,0,0" Height="90" Width="90">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Button.Template>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80*">
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Image Source="/MyProject.Wpf;component/Icons/customer-icon.png" Margin="10" Grid.Row="0" Width="Auto"/>
<TextBlock Foreground="Black" Margin="0,0,0,3" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" >Izlaz</TextBlock>
</Grid>
</Button>
So could I somehow achieve this (image + text IN MY button ) also to create it programatically.
Define a style in your App.xaml:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style x:Key="theStyle" TargetType="Button">
<Setter Property="FontSize" Value="15" />
<Setter Property="BorderThickness" Value="1.5" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<!-- and so on for each property...-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
You can then apply this style to any Button in your application, either in XAML:
<Button x:Name="btnAddNewItem" Style="{StaticResource myStyle}"/>
...or programmatically:
Button button = new Button();
button.Style = Application.Current.Resources["myStyle"] as Style;
I just need to separate two grous of buttons inside StackPanel with something like:
---------Another Buttons--------
but I need a solid line, note --
I made a custom control for this.
The code for the Generic.xaml
<Style TargetType="{x:Type local:LineControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:LineControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Separator Grid.Column="0" VerticalAlignment="Center"></Separator>
<ContentPresenter Grid.Column="1" Content="{TemplateBinding Content}" VerticalAlignment="Center"></ContentPresenter>
<Separator Grid.Column="2" VerticalAlignment="Center"></Separator>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
The C# code:
public class LineControl : ContentControl
{
static LineControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(LineControl), new FrameworkPropertyMetadata(typeof(LineControl)));
}
}
And you use it like this
<local:LineControl>
<TextBlock>test</TextBlock>
</local:LineControl>
The TextBlock can be any control. You can even put a StackPanel with buttons in it if you want.
<StackPanel Orientation="Horizontal">
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
</StackPanel>
try this
How to wrap text in GroupBox header? This code doesn't work.
<GroupBox>
<GroupBox.Header>
<TextBlock Text="qwertyuiopasdfghjklqwertyuiopasdfghjkl" TextWrapping="Wrap"/>
</GroupBox.Header>
In-order to get the text content wrapped,You have to specify the width, other wise the with of the textblock automatically set to the length of content in the text block.
<TextBlock Width="150" Text="qwertyuiopasdfghjklqwertyuiopasdfghjkl" TextWrapping="Wrap"/>
While the solution to set the header's width by explicitly specifying the value or binding with another element works perfectly, delving into the default style of GroupBox, I found that making small modifications into the style will solve this issue.
<BorderGapMaskConverter x:Key="BorderGapMaskConverter"/>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="BorderBrush" Value="#D5DFE5"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupBox}">
<Grid SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6"/>
<!-- <ColumnDefinition Width="Auto"/> is removed because its Width="Auto" is problematic. -->
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="6"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="6"/>
</Grid.RowDefinitions>
<!-- The value of Grid.ColumnSpan is changed from 4 to 3. -->
<Border Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="3"
BorderBrush="Transparent"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="4"/>
<!-- The value of Grid.ColumnSpan is changed from 4 to 3. -->
<Border Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="3"
BorderBrush="White"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4">
<Border.OpacityMask>
<MultiBinding Converter="{StaticResource BorderGapMaskConverter}"
ConverterParameter="7">
<Binding ElementName="Header" Path="ActualWidth"/>
<Binding RelativeSource="{RelativeSource Self}" Path="ActualWidth"/>
<Binding RelativeSource="{RelativeSource Self}" Path="ActualHeight"/>
</MultiBinding>
</Border.OpacityMask>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="3">
<Border BorderBrush="White"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="2"/>
</Border>
</Border>
<!-- HorizontalAlignment="Left" is added to adjust the surrounding line. -->
<Border x:Name="Header"
Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
HorizontalAlignment="Left"
Padding="3,1,3,0">
<ContentPresenter ContentSource="Header"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<!-- Grid.ColumnSpan="2" is removed because it is no longer necessary. -->
<ContentPresenter Grid.Column="1" Grid.Row="2"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The root cause of this issue is Width="Auto" of the 2nd ColumnDefinition of Grid. So remove the ColumnDefinition so that the header's Border is assigned to the original 3rd ColumnDefinition. Then add HorizontalAlignment="Left" to the header's Border. Some trivial edits of ColumnSpan. That's it.
This modified style lets WPF's layout engine determine the header's width automatically depending on actual width of GroupBox. No need to care about the width each time. As far as I know, there is no noticeable degradation from the default one.
The Search Bar in Windows 8.1 has a default search icon attached to it .
Like This
Is there any way i can get rid of that icon ?
You need to edit style of SearchBox to remove search button.
To get style of SearchBox follow below steps
Step 1 : http://i.imgur.com/tg8icLv.png
Step 2 : http://i.imgur.com/VdB28oY.png and Press Ok
Step 3 : http://i.imgur.com/9wNmQga.png
<Style x:Key="SearchBoxStyle1" TargetType="SearchBox">
..........................
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="SearchBox">
......
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="SearchTextBox" BorderThickness="0" Background="Transparent" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" InputScope="Search" MinHeight="{ThemeResource SearchBoxTextBoxThemeMinHeight}" MaxLength="2048" Padding="{TemplateBinding Padding}" PlaceholderText="{TemplateBinding PlaceholderText}" Style="{StaticResource SearchTextBoxStyle}" TextWrapping="NoWrap" VerticalAlignment="Stretch"/>
<Button x:Name="SearchButton" Height="0" Width="0" AutomationProperties.AccessibilityView="Raw" Background="Transparent" Grid.Column="1" FontWeight="{ThemeResource SearchBoxButtonThemeFontWeight}" Style="{StaticResource SearchButtonStyle}"/>
.......
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SearchBox Height="35" Width="200" Style="{StaticResource SearchBoxStyle1}"/>
I currently have a custom TabItem which has a custom header, which is defined as part of a Style like this:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type t:TwitterListTabItem}">
<Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" Margin="0,-2,0,0" >
<Grid SnapsToDevicePixels="true">
<ContentPresenter x:Name="Content" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header" RecognizesAccessKey="True" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="{TemplateBinding Padding}"/>
<Button x:Name="PART_Close" HorizontalAlignment="Right" Margin="0" Padding="4" VerticalAlignment="Top" Width="16" Height="16" Style="{DynamicResource CloseableTabItemButtonStyle}" ToolTip="Close Tab">
<Path x:Name="Path" Stretch="Fill" StrokeThickness="0.5" Fill="#FFFFFF" Data="F1 M 2.28484e-007,1.33331L 1.33333,0L 4.00001,2.66669L 6.66667,6.10352e-005L 8,1.33331L 5.33334,4L 8,6.66669L 6.66667,8L 4,5.33331L 1.33333,8L 1.086e-007,6.66669L 2.66667,4L 2.28484e-007,1.33331 Z " HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Button>
<Button x:Name="PART_Number" HorizontalAlignment="Right" Padding="0" Margin="0" VerticalAlignment="Bottom" Width="16" Height="16" Style="{DynamicResource CloseableTabItemNumberStyle}" ToolTip="New Tweets" Content="{TemplateBinding NewTweetsNumber}" />
</Grid>
</Border>
<ControlTemplate.Triggers>
.....Triggers Removed for Shortness....
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter
Now I want to set the template for the content area of the TabItem. I cannot work out how to do this. I have tried setting ContentTemplate, with a <ControlTemplate> containing a ListBox, but it didn't work.
So how do i define a template to control the content?
Thanks in advance
Use the TabItem.HeaderTemplate property for your tab header, and the TabItem.Template property for your tab's contents. Example.
Looks like you need one more ContentPresenter which displays the Content. And you already have a ContentPresenter which is displays Header.
<ContentPresenter ContentSource="Content"/>