Good day,
I have several buttons in my WPF application that use a pre-made style template.
In this template is once the content (text) and an image.
This image should be, depending on the button, a different one or no one.
The "Settings_Button" uses the style of the "Pagebutton".
This style contains how the button is built. There is also an Image in it. How do I access the source property of the image?
Unfortunately I haven't found a solution for this online and I'm still relatively new in this area.
[The Style Template, the Buttons are using]
<!--PageButton-->
<Style x:Key="Pagebutton" TargetType="Button">
<Setter Property="Width" Value="200"/>
<Setter Property="FontFamily" Value="{StaticResource Roboto}"/>
<Setter Property="Foreground" Value="{DynamicResource FntBtnColor_Page}"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Margin" Value="5 5 5 5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="borderBtn" CornerRadius="3" Background="#E00047" >
<Grid>
<Image x:Name="Pagebutton_Image" HorizontalAlignment="Right" Height="15" Width="15" Margin="0 0 20 0"/>
<ContentPresenter x:Name="contentPresenterBtn" HorizontalAlignment="Center" VerticalAlignment="Center" Focusable="False" RecognizesAccessKey="True"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
[The Usage of the Style]
<Button x:Name="Settings_Button" Style="{DynamicResource Menuebutton}" Content="{x:Static p:Resources.Menue_settings}" Click="Settings_Click"/>
Related
I try to create a TextBox with a little triangle at the top right corner. I don't really know how to achieve it. I tried to add a polygon to the textbox at this way:
<TextBox
x:Name="PartnerEmail"
TextWrapping="Wrap"
MaxLength="50"
Grid.Column="1"
Grid.Row="12"
Margin="5,1,0,1" >
<TextBox.Style>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Polygon Points="0,0 10,0 0,10 0,0" Margin="0,2,2,0" HorizontalAlignment="Right" Fill="#fcba03" FlowDirection="RightToLeft"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
But obviously it's not gonna work because I override the default template, so after this, all I have is a polygon and the textbox disappears. Can anyone have a good solution for this?
You are on the right track, but are working a bit too hard...
The thing to keep in mind about UI elements in WPF is that they work in layers. Think of elements as a composite of smaller items that you want to stack in a 3-D space. You aren't just working in a 2 dimensional drawing space anymore like a GDI rendering space of WinForms.
So lets logically think about what you want to do here. Lets try to achieve several goals in our solution:
Lets make a control template that will allow us to reuse our newly minted control.
Lets make the control completely portable in 3 dimensional space i.e. no use of raster images that will distort if we resize our control - lets stick to geometry only for drawing.
Lets make it easy to decide how large to make the triangle in the corner.
Lets decide to allow easy modifications for later, such as triangle placement (you want to change its location), hit testing (should it be part of the text surface or the border?), color (again, border or text?), etc.
Ok, to solve this, I alluded to the idea of objects in layers. Lets divide our drawing surface into a grid:
That means we want to use a Grid control. We want to define two rows and two columns, and we want to TextBox to cover all 4 cells. We will make sure to set the Rowspan and Columnspan to fill the grid.
We will then add a 2nd item, our Polyline triangle to row 1 column 1, and add it after the text box. That way it's Z-order will be on top.
Here then is the control template:
<Window.Resources>
<Style x:Key="TriangleTextBox" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10"/>
<RowDefinition Height="6*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<TextBox Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" Margin="0,0,0,0" Text="{TemplateBinding Text}" BorderThickness="1"/>
<Polygon Grid.Row="0" Grid.Column="1" Points="0,0 10,0 0,10 0,0" Fill="Black" FlowDirection="RightToLeft"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Note that we set the key to "TriangleTextBox".
Now its just a simple matter of using our control template as follows:
<Grid>
<TextBox Style="{StaticResource ResourceKey=TriangleTextBox}" Width="100" Height="20"/>
</Grid>
And there you have it:
You can expand on this from there.
You are essentially replace the entire textbox by nothing but a triangle. You should copy the base template, and modify it from there:
<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
<Style x:Key="TextBoxStyle1" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<!--<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>-->
<Grid>
<Polygon Points="0,0 10,0 0,10 0,0" Margin="0,2,2,0" HorizontalAlignment="Right" Fill="#fcba03" FlowDirection="RightToLeft"/>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
As for the template itself, you get it from microsoft, or via visual studio.
Create a user (composite) control which would have the polygon (drawn last) to overlay a textbox in the corner as needed. Usage of a Canvas control for specific placement or within a Grid for general placement in the control.
Here is where I had to put a search icon over a text field in a grid. I set the ZIndex as needed.
Code
<TextBox Grid.ColumnSpan="2"
Panel.ZIndex="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<Image Grid.Column="1" Source="../Assets/Search.png"
Panel.ZIndex="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Stretch="Uniform"/>
I've got about 300+ buttons that are represented in a grid. When I try to render this, it takes a good 5 seconds to load up all buttons. Is there any alternative? Functionality that already exists such as hover over, mouse enter, left button click etc are all needed... just wondering if there is a way to speed up button rendering.
Buttons are created dynamically in a grid, with an ItemsControl, that contains an ItemsPanelTemplate (that is just a grid definition of width and height), a DataTemplate in ItemsControl.Resources, where the ToggleButton(s) that are created dynamically (300+) are created.
The datatemplate in the ItemsControl.Resources looks like this:
<DataTemplate DataType="{x:Type engine:Weodel}">
<ToggleButton
Tag="{Binding}"
IsChecked="{Binding IsSelected}"
Height="{Binding ElementName=weItemControl,
Path=DataContext.ButtonHeightWidth}"
Width="{Binding ElementName=weItemControl,
Path=DataContext.ButtonHeightWidth}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Margin="{Binding ElementName=weItemControl,
Path=DataContext.ButtonMarginToUse}"
Padding="2"
Style="{StaticResource WeButton}">
</ToggleButton>
</DataTemplate>
The style of the button in resource dictionary:
<Style TargetType="{x:Type ToggleButton}" x:Key="WeButton">
<Setter Property="Background" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextBlock.TextAlignment="Center">
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="TextAlignment" Value="Center"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Background" Value="{Binding GColour}"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Background" Value="{Binding GColour}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm building WPF application and I want to use icons from Font Awesome. I have Font Awesome included in styles, and a font family specified in fields where I want to use it. The problem is icons are showing properly in the design window but change to crossed squares during runtime.
There is my Fonts XAML
<FontFamily x:Key="ArconRegular">pack://application;,,,/Fonts/#Arcon</FontFamily>
<FontFamily x:Key="ArconRounded">pack://application;,,,/Fonts/#Arcon Rounded-</FontFamily>
<FontFamily x:Key="FASolid">pack://application;,,,/Fonts/#Font Awesome 5 Free Solid</FontFamily>
<Style TargetType="{x:Type Control}" x:Key="BaseStyle">
<Setter Property="FontFamily" Value="{StaticResource ArconRegular}"/>
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="BaseTextBlockStyle">
<Setter Property="FontFamily" Value="{StaticResource ArconRegular}"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseStyle}"/>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseStyle}"/>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseStyle}"/>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseTextBlockStyle}"/>
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource BaseStyle}"/>
<system:String x:Key="FAMinimizeIcon"></system:String>
<system:String x:Key="FAMaximizeIcon"></system:String>
<system:String x:Key="FACloseIcon"></system:String>
The Buttons XAML (I want to use icons on buttons)
<Style TargetType="{x:Type Button}" x:Key="WindowControlButton" BasedOn="{StaticResource BaseStyle}">
<Setter Property="FontFamily" Value="{StaticResource FASolid}"/>
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="Foreground" Value="{StaticResource ForegroundMainBrush}"/>
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleX="1.5"/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource BackgroundLightBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
And finally MainWindow XAML (a part of it where i want to use them)
<!-- Window Buttons -->
<StackPanel Grid.Column="2" Orientation="Horizontal">
<Button Style="{StaticResource WindowControlButton}" Content="{StaticResource FAMinimizeIcon}" Command="{Binding MinimizeCommand}"/>
<Button Style="{StaticResource WindowControlButton}" Content="" Command="{Binding MaximizeCommand}"/>
<Button Style="{StaticResource WindowCloseButton}" Content="" Command="{Binding CloseCommand}"/>
</StackPanel>
As you can see, I tried specifying icon code in separate string and using StaticResource but nothing works.
In my case it was missing FontFamily="{TemplateBinding FontFamily}" in the ControlTemplate
Had a same issue, i.e Showing ok in Design mode but no Runtime. For me it was because fontawesome was not included in the assembly.
Changed (in visual studio) the .otf file's Build Action to "Resource". You may want to check if the file is included in your assembly by decompiler.
I have a button that i want to have a dynamic color based on if a file exists.
I am using two resources to do this, one resource is a color and one is a SolidColorBrush. They are declared as so
<Window.Resources>
<Color x:Key="ColorName">Red</Color>
<SolidColorBrush x:Key="ButtonColor1" Color="{StaticResource ColorName}" />
</Window.Resources>
Now, my button is done in a strange way as i wanted to change the highlight color, its done as so
Button Grid.Row="1" Grid.Column="2" Height="25" Width="25"
HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click"
Name="SalutButton">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{StaticResource
ButtonColor1}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderBrush="Black" BorderThickness="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightGreen"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
My code to try and change the resource is:
Resources["ColorName"] = System.Windows.Media.Colors.Green;
This successfully changes the resource colorname, but the buttoncolor1 resource is already made during initialisation and takes the default color of colorname which is red, so even though im changing the resource its not updating.
Any ideas?
I need to customize the Microsoft.Phone.Controls.Rating control. Below code creates a template a bit closer but i need to change icons.
<Style x:Key="RatingStyle" TargetType="toolkit:Rating">
<Setter Property="AllowHalfItemIncrement" Value="True" />
<Setter Property="Width" Value="100" />
<Setter Property="Height" Value="20" />
<Setter Property="FilledItemStyle">
<Setter.Value>
<Style TargetType="toolkit:RatingItem">
<Setter Property="Background"
Value="#FF9900" />
</Style>
</Setter.Value>
</Setter>
<Setter Property="UnfilledItemStyle">
<Setter.Value>
<Style TargetType="toolkit:RatingItem">
<Setter Property="Background"
Value="#E0E0E0" />
</Style>
</Setter.Value>
</Setter>
</Style>
My required templates are 2, 1 for place rating and one for average price level (shown by $ sign). below is the image showing my requirement.
I find the quickest method is to change the Template of the two styles to adjust the image/look:
<Style x:Name="UnfilledDollarStyle" TargetType="toolkit:RatingItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="toolkit:RatingItem">
<Border HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock FontSize="30" Foreground="Silver">$</TextBlock>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Name="FilledDollarStyle" TargetType="toolkit:RatingItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="toolkit:RatingItem">
<Border HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock FontSize="30" Foreground="Green">$</TextBlock>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In use:
<toolkit:Rating UnfilledItemStyle="{StaticResource UnfilledDollarStyle}"
FilledItemStyle="{StaticResource FilledDollarStyle}" Value="2" />
By editing the Template, you could use images or whatever you'd like within each RatingItem.
Of course, you could leave the unfilled style "empty" or completely transparent so that no symbols are shown at all. (To keep consistent spacing around the control, I'd suggest using a fully transparent symbol rather than no content). Here, I've set the Opacity to 0:
<TextBlock FontSize="30" Opacity="0">$</TextBlock>