XAML button with rounded edged with perfect semicircle at the sides - xaml

I have been trying for sometime now to create a button with rounded edges whose rounded edges are actually semicircles.
My idea of implementing this is to bind the CornerRadius of the Border to the half the height of the button (I know there's no way I can do a calculation in XAML, except maybe a converter). Alas, that seems impossible because TemplateBinding doesn't bring up any suggestion.
<ControlTemplate TargetType="Button">
<Grid>
<Border CornerRadius={???}>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"
FontSize="{TemplateBinding FontSize}"
FontFamily="{TemplateBinding FontFamily}" />
</Border>
</Grid>
</ControlTemplate>
Maybe I might have to create a new control derived from button with a CornerRadius dependency property. But before I go ahead, is there anyway to achieve it in XAML?
By the way, if it matters, I'm doing it for a UWP app?

But before I go ahead, is there anyway to achieve it in XAML?
Yes, I think this is possible. But converter is needed
I know there's no way I can do a calculation in XAML, except maybe a converter
Yes, we need to calculate in the converter and the CornerRadius is a CornerRadius type, we can't directly binding a double type of Height/2 to it. Here I used Button's height to calculate the radius.
My idea of implementing this is to bind the CornerRadius of the Border to the half the height of the button.
I think there is no need to use a Border for the ControlTemplate of Button, Grid and ContentPresenter also have the CornerRadius property.
For example here:
<ControlTemplate TargetType="Button">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}"
CornerRadius="{Binding Height, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource cvt}}">
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
Content="{TemplateBinding Content}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
CornerRadius="{Binding Height, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource cvt}}" />
</Grid>
</ControlTemplate>
<local:HeightToCornerRadiusConverter x:Key="cvt" />
My HeightToCornerRadiusConverter is like this:
public class HeightToCornerRadiusConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var height = (double)value;
CornerRadius radius = new CornerRadius(height / 2);
return radius;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
There is a problem here, as you can see that the CornerRadius is bound to the Height of the Button, so it is important that we need to set a height to Button when we use this style.

Related

How to vertically align XAML UWP checkbox

I am trying to vertically align a checkbox. The actual box appears at the top. I want it to appear in the middle.
This is the XAML:
<CheckBox FontSize="100" Content="Test" VerticalContentAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" HorizontalContentAlignment="Center"/>
This is what it looks like:
I have seen similar questions on SO, but the answer was to use VerticalContentAlignment. This does not work. Some answers have suggested using negative padding or margins, which does not scale. So please don't mark as duplicate, this has not really been answered. Or perhaps it was answered for WPF but not for UWP.
I am aware that you can change the style of the control, but that is a lot of work for something that should just work out of the box.
I am using VS 2019 16.6.2 with UWP v6.2.10
Update
This is what I would like my CheckBox to look.
How to vertically align XAML UWP checkbox
For the requirement, the better way is modify the checkbox's default layout. The default layout is Column, we need to change it to Row. And I will share the a part of style and you could use it directly.
<Grid
x:Name="RootGrid"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid
Height="32"
HorizontalAlignment="Center"
VerticalAlignment="Top"
>
<Rectangle
x:Name="NormalRectangle"
Width="20"
Height="20"
Fill="{ThemeResource CheckBoxCheckBackgroundFillUnchecked}"
Stroke="{ThemeResource CheckBoxCheckBackgroundStrokeUnchecked}"
StrokeThickness="{ThemeResource CheckBoxBorderThemeThickness}"
UseLayoutRounding="False"
/>
<FontIcon
x:Name="CheckGlyph"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="20"
Foreground="{ThemeResource CheckBoxCheckGlyphForegroundUnchecked}"
Glyph=""
Opacity="0"
/>
</Grid>
<ContentPresenter
x:Name="ContentPresenter"
Grid.Row="1"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="Center"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
TextWrapping="Wrap"
/>
For the complete style please refer this link.
Update
If do not want to edit the default style, we could make custom checkbox, and edit the layout in OnApplyTemplate method.
public class CustomCheckBox : CheckBox
{
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var normalRectangle = GetTemplateChild("NormalRectangle") as Rectangle;
var rootGrid = normalRectangle.Parent as Grid;
Grid.SetColumnSpan(rootGrid, 2);
rootGrid.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center;
var contentPresenter = GetTemplateChild("ContentPresenter") as ContentPresenter;
Grid.SetColumn(contentPresenter, 0);
Grid.SetColumnSpan(contentPresenter, 2);
contentPresenter.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center;
}
}
Usage
<local:CustomCheckBox FontSize="100" Content="Test" VerticalAlignment="Center" HorizontalAlignment="Center" />
Update 1
use the following to replace OnApplyTemplate content.
var normalRectangle = GetTemplateChild("NormalRectangle") as Rectangle;
var rootGrid = normalRectangle.Parent as Grid;
Grid.SetColumnSpan(rootGrid, 2);
rootGrid.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Left
rootGrid.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center;

Update color of SelectionIndicator in NavigationView

I'm using the NavigationView control to provide the left pane hamburger menu navigation in my UWP app.
I'd like to change the color of the selection indicator (the little rectangle that shows up next to the item you selected).
In generic.xaml I can see the color is being set to the system accent color:
<Style TargetType="NavigationViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="NavigationViewItem">
<Grid
x:Name="LayoutRoot"
Height="40"
Background="{TemplateBinding Background}"
Control.IsTemplateFocusTarget="True">
<!-- Wrap SelectionIndicator in a grid so that its offset is 0,0 - this enables the offset animation. -->
<Grid
HorizontalAlignment="Left"
VerticalAlignment="Center">
<Rectangle
x:Name="SelectionIndicator"
Width="6"
Height="24"
Fill="{ThemeResource NavigationViewSelectionIndicatorForeground}"
Opacity="0.0"/>
</Grid>
<Border
x:Name="RevealBorder"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" />
<Grid Height="40" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="IconColumn" Width="48" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Viewbox x:Name="IconBox"
Child="{TemplateBinding Icon}"
Margin="16,12"/>
<ContentPresenter x:Name="ContentPresenter"
Grid.Column="1"
ContentTransitions="{TemplateBinding ContentTransitions}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is there a way in my pages XAML file (that uses the NavigationView) to change the color of the rectangle Fill from NavigationViewSelectionIndicatorForeground to some value I set?
I know I could copy over the entire template and update the copy, and set the template on the NavigationView, but it seems like a lot of overhead just to change one value.
You can just define your own brush with x:Key="NavigationViewSelectionIndicatorForeground" for example in App.xaml:
<Application ...>
<Application.Resources>
<SolidColorBrush x:Key="NavigationViewSelectionIndicatorForeground"
Color="Yellow" />
</Application.Resources>
</Application>
Alternatively you could also declare the resource in the scope of your Page or even in your NavigationView's Resources, it just needs to be in the path in the XAML tree leading to the NavigationView.
Because your resource goes later in the cascade, it will override the default NavigationViewSelectionIndicatorForeground with your defined brush.

How to vertically centre text in a Xamarin Forms Entry on UWP?

I have a Xamarin Forms project (v2.5) where I have a text Entry control in my Xaml file. I need the entry to be taller than default, so I specify a HeightRequest of 60, which works fine, apart from the text itself is aligned to the top of the Entry control.
<Entry Text="{Binding CustomerNameText}" HeightRequest="60" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" IsEnabled="{Binding CustomerNameEntryEnabled}" Focused="Entry_Focused" Unfocused="Entry_Unfocused" />
Which looks like:
I added a custom renderer:
public class CustomEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(this.Control != null)
{
this.Control.VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center;
this.Control.Height = 60;
}
}
}
But this doesn't work. The HeightRequest in the Xaml doesn't seem to work anymore, so I added the height in the custom renderer. But the text alignment stays at the top.
Can anyone tell me how to get the text vertically centered?
The correspondent native control of Entry is TextBox in UWP app, see Renderer Base Classes and Native Controls for more details. The VerticalAlignment property means that setting current control to vertical center in the parent control, not for the text inside. Only properties like TextAlignment will take effects on the text. Since Textbox in UWP app doesn't have the property VerticalTextAlignment, you cannot set the text to vertical center directly. But you could change the style template of TextBox as a workaround.
Create a new style for the Textbox, and to set the VerticalAlignment property to center to both ContentPresenter and ScrollViewer controls inside the ControlTemplate. And then apply the style in the custom render.
The style in App.xaml
<Style x:Key="TextBoxStyle1" TargetType="TextBox">
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
...
<Border x:Name="BorderElement" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Grid.ColumnSpan="2" Grid.RowSpan="1" Grid.Row="1"/>
<ContentPresenter x:Name="HeaderContentPresenter" VerticalAlignment="Center" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" Grid.ColumnSpan="2" FontWeight="Normal" Foreground="{ThemeResource TextControlHeaderForeground}" Margin="0,0,0,8" Grid.Row="0" TextWrapping="{TemplateBinding TextWrapping}" Visibility="Collapsed" x:DeferLoadStrategy="Lazy"/>
<ScrollViewer x:Name="ContentElement" VerticalAlignment="Center" AutomationProperties.AccessibilityView="Raw" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsTabStop="False" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Grid.Row="1" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" ZoomMode="Disabled"/>
<TextBlock x:Name="PlaceholderTextContentPresenter" Grid.ColumnSpan="2" Foreground="{Binding PlaceholderForeground, RelativeSource={RelativeSource Mode=TemplatedParent}, TargetNullValue={ThemeResource TextControlPlaceholderForeground}}" IsHitTestVisible="False" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Grid.Row="1" Text="{TemplateBinding PlaceholderText}" TextWrapping="{TemplateBinding TextWrapping}" TextAlignment="{TemplateBinding TextAlignment}"/>
<Button x:Name="DeleteButton" AutomationProperties.AccessibilityView="Raw" BorderThickness="{TemplateBinding BorderThickness}" Grid.Column="1" FontSize="{TemplateBinding FontSize}" IsTabStop="False" MinWidth="34" Margin="{ThemeResource HelperButtonThemePadding}" Grid.Row="1" Style="{StaticResource DeleteButtonStyle}" VerticalAlignment="Stretch" Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Custom render:
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
this.Control.Height = 60;
Control.Style = (Windows.UI.Xaml.Style)App.Current.Resources["TextBoxStyle1"];
}
}
I don't think that is needed a custom renderer, just center and expand.
VerticalOptions = "LayoutOptions.CenterAndExpand"
I know it's late, but below code works for Android to center text in Entry,it shuold work for UWP too:
this.Control.Gravity = GravityFlags.CenterHorizontal;
this.Control.Gravity = GravityFlags.Center;
Let me know,if it helps
//Try this:
VerticalOptions = "CenterAndExpand"
If this doesn't work go for custom renderer

WP7 Mango: Retemplating PhoneApplicationFrame created "Unspecified Error" exception

The following used to work in WP 7.0:
I'm attempting to re-template the root PhoneApplicationFrame in my Mango beta 2 refresh (7712) project with the following Xaml:
<Style TargetType="phone:PhoneApplicationFrame" x:Key="FrameStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border x:Name="ClientArea" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" >
<Grid>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
<toolkit:PerformanceProgressBar IsIndeterminate="True" VerticalAlignment="Top" Margin="0,8,0,0" Visibility="{Binding Path=GlobalProgressVisibility, Source={StaticResource RootFrameViewModel}}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When the application launches I get an App.UnhandledException with the text "Unspecified error" and no stack trace. Has anyone seen this?
Blend was helpful in pointing out some properties that shouldn't be set in Mango. Removing the Content and ContentTemplate properties fixed the issue.
I can't reproduce exactly your problem, but I had the same error retemplating a listbox.
Try setting the TargetType property on the ControlTemplate (worked for me) :
<ControlTemplate TargetType="phone:PhoneApplicationFrame">

ProgressbarStyle issues

I have a ProgressbarStyle in which I add a TextBlock-Control to the Grid "DeterminateRoot". This TextBlock should display a Status-Text, which I change manually in CodeBehind and this works already.
Here is the part of my style, which I change in the standard ProgressbarStyle:
<Grid x:Name="DeterminateRoot" Margin="1">
<Rectangle x:Name="ProgressBarIndicator" Fill="{TemplateBinding Foreground}" HorizontalAlignment="Left" Margin="{TemplateBinding BorderThickness}" RadiusY="1.5" RadiusX="1.5" StrokeThickness="0.5"/>
<TextBlock x:Name="txtbStatusText" Text="5 of 20" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Black" FontWeight="Bold" FontFamily="Arial" FontSize="11"></TextBlock>
</Grid>
My question is: How can I change the Foregroundcolor of the TextBlock-Text to black, without changing the standardcolor of the progressbar? Because, when I delete the Fill-Property of the Rectangle (ProgressBarIndicator), then I can change the ForegroundColor of my TextBlock, but I want to keep the standardlook of the Progressbar!
Thank you in advance for your answers!
Best Regards
Dougy
As you are stating, if you set booth properties to the same TemplateBinding your text will be invisible. You have to create another property so you can manage them independently.
Create in your code a dependency property of type Brush and then template binding your TextBlock to that property.