Rounded corners are not supported on UWP Forms. This article expains how to achieve rounded corners on Win Phone:
wintellect.com/devcenter/jprosise/supercharging-xamarin-forms-with-custom-renderers-part-1
This didn't work on UWP, after much digging I was able to get something that almost works, by changing the OnSizeChanged handler:
` private void OnSizeChanged(object sender, EventArgs e)
{
var button = (Xamarin.Forms.Button)sender;
Control.ApplyTemplate(); var grids = Control.GetVisuals<Grid>(); foreach (var grid in grids) { grid.CornerRadius = new CornerRadius(button.BorderRadius); } var presenters = Control.GetVisuals<ContentPresenter>(); foreach (var presenter in presenters) { presenter.CornerRadius = new CornerRadius(button.BorderRadius); } button.SizeChanged -= OnSizeChanged; }`
In the original code Control.GetVisuals(); never returned any borders.....
Anyway my code works so long as I don't set a background color:
<Button Text="Click Me" BorderRadius="32" BorderWidth="8"/> <Button Text="Click Me2" BorderRadius="32" BorderWidth="8" BackgroundColor="Blue"/>
If I set a background color I'm left with the corners. This is driving me crazy! Any suggestions?
Thanks,
Philip
Posts
Any advise? Still stuck on this.......
@PhilipOGorman - The BackgroundColor does include the area outside the border, so even if you put rounded corners on (as follows), the background color remains.
What you may want to do is to use Color.Transparent for the area outside the border, and a different color for inside the border. One of those should be linked to BackgroundColor, the other should be linked to another attribute on a roundbutton custom control. Although it feels wrong to do it this way, it's probably easier to use BackgroundColor=Transparent for the bit outside the border, and paint the area inside the border yourself.
This problem with the corners pre-dates UWP - I raised a bug against Xamarin.Forms on WinRT quite a while back, details at:
https://bugzilla.xamarin.com/show_bug.cgi?id=31670 . That bug has been marked as IN PROGRESS for nearly 7 months :-(
@JohnHardman Thanks for the feedback! I'm a little closer I think. But I cannot make my background color transparent from my renderer. Here is an experiment I ran:
`private void OnSizeChanged(object sender, EventArgs e)
{
//disabled for now
var button = (Xamarin.Forms.Button)sender;
<Button Text="Click Me" BorderRadius="32" BorderWidth="8"/> <Button Text="Click Me2" BorderRadius="32" BorderWidth="8" BackgroundColor="Blue"/>
As you can see, I have control over everything within the border of my button, but I cannot clear the Background set in the xaml. I may have to create my own button with a custom property called UWPBackground and then fill that background in the renderer.
Do you have any idea how to set the complete Background color from the renderer?
@JohnHardman Ok - very close to what I want now, but the pushed color of the button is not correct, it is based on what ever the color of the parent control is - in the images below normally the pressed color of the button should be a lighter blue, but because no background color is set in the button control it is set to gray.
Anyway here is the code for the rounded button - if anyone has improvements please share!
`
}`
`
public class RoundedButton : Button
{
public Color UWPBackground
{
get { return (Color)GetValue(UWPBackgroundProperty); }
set
{
SetValue(UWPBackgroundProperty, value);
}
}
<controls:RoundedButton Text="Click Me2" BorderRadius="32" BorderWidth="8" UWPBackground="Blue"/>
@PhilipOGorman - Apologies for delay in replying. Will try to take a look later this week.
@JohnHardman I came across this article button styles
I wonder if the renderer can load a button style?
@PhilipOGorman - certainly stuff I have read before has made it sound like styles are an easier way of changing how buttons look on Windows (this was from when I was looking to see how to get rid of the margin around the outside).
My day is quickly running out, but I'm still hoping to take a look at this if I can find time at the weekend.
@PhilipOGorman - If you don't want to go down the style route, you can create within your renderer an instance of a custom control based on Windows.UI.Xaml.Controls.UserControl, containing a Windows.UI.Xaml.Controls.Button. It should be possible to set the Background on that to a Transparent brush and the Opacity to 0. You can then paint over this whatever you need, including a circular Border.
The XML comment for UserControl says:
// Summary:
// Provides the base class for defining a new control that encapsulates related
// existing controls and provides its own logic.
@JohnHardman I'm getting closer. By setting the presenter color it is no longer grey (because in my case the parent background is black). However it's still not right though because:
1) the presenter brush is always on top. So if the grid and presenter color are the same nothing changes when the button is pressed. So to give some effect I make the presenter color the same and add some transparency. But it doesn't look great.
2) The border when pressed is still grey. I can't figure out how to change it.
` private void OnSizeChanged(object sender, EventArgs e)
{
var button = (RoundedButton)sender;
var color = button.UWPBackground;
Control.ApplyTemplate();
I've looked in to loading a xaml template - it's not too difficult. The hard part is creating the template. I'll post some code later.
I'll check out custom control too
Here is an example showing how to aplly a control template. I just have to figure out how to create the template I want.
`
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
var button = (RoundedButton)e.NewElement;
if (Control != null)
{
button.SizeChanged += OnSizeChanged;
Control.Template = GetTemplate();
Control.ApplyTemplate();
}
@JohnHardman I was successfully able to load a style from the App.xaml resources. The code is quite simple.
The trouble is creating a style to do what I wanted to do, this is not a xamarin issues, I think in UWP it is not straight forward to use the standard button and give it rounded corner. I think I need to take the discussion to a windows forum.
Right now I have to create a new style for each different button color I want to use. If I specify the color when I add a button I get the nasty corners. Here is the code:
` public class CustomButtonRenderer : ButtonRenderer
{
<Style TargetType="Button" x:Key="BlueRoundedButtonStyle"> <Setter Property="Background" Value="Blue" /> <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/> <Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundTransparentBrush}" /> <Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" /> <Setter Property="Padding" Value="8,4,8,4" /> <Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" /> <Setter Property="FontWeight" Value="Normal" /> <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" /> <Setter Property="UseSystemFocusVisuals" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid x:Name="RootGrid" Background="{TemplateBinding Background}" CornerRadius="6"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"> <Storyboard> <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" /> </Storyboard> </VisualState> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" /> </ObjectAnimationUsingKeyFrames> <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" /> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="LightBlue" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" /> </ObjectAnimationUsingKeyFrames> <PointerDownThemeAnimation Storyboard.TargetName="RootGrid" /> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledTransparentBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <ContentPresenter x:Name="ContentPresenter" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Content="{TemplateBinding Content}" ContentTransitions="{TemplateBinding ContentTransitions}" ContentTemplate="{TemplateBinding ContentTemplate}" Padding="{TemplateBinding Padding}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" AutomationProperties.AccessibilityView="Raw" CornerRadius="6"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
@PhilipOGorman - I haven't used ControlTemplates yet, so cannot comment on that way of doing things.
After some experimentation, it looks like it might be necessary, after creating a control based on UserControl, to change BorderBrush in handlers for GotFocus and LostFocus to get the desired effect. I'm not an expert on Windows UI - I've been doing a bit of trial-and-error stuff, which isn't really how I like to work. Hope that points you in the right direction - not sure I can help further without spending a lot of time on it.
Ok - come back to think Forms is causing the problem. I have the effect I want on a native UWP app here:
https://bitbucket.org/pogorman_jca/uwpbutton
If I load this style in a renderer in a Forms app it still has the nasty corners (in the color of the button background).
When forms creates the button it paints the entire rectangle of the button the specified background color. There is nothing from the renderer I can do to clear that color.
As a suggestion, you could always make you own Renderer that inherits from ViewRenderer and replaces the button renderer.
You would need to implement the same things as the button to keep it consistent, but then you could just insert an entirely new control instead of using the broken Xamarin button.
@AdamMeaney I'm not sure how to do that - something like this?
`public class CustomButtonRenderer : ViewRenderer<RoundedButton, FormsButton>
{
But the Control of ViewRenderer is private I cannot assign it.
Do you know of any examples on how to do this?
Thanks!
It would be kind of like this.
Just replace the camera crap with an actual Button from Xamarin for the View, and your own implementation for the Renderer.
If you want to follow their code more, use a decompiler to look at the DLLs and copy as much as you think is useful.
@AdamMeaney Thanks!
@AdamMeaney @PhilipOGorman - I think we're suggesting the same thing - a custom control based on Windows.UI.Xaml.Controls.UserControl, containing a Windows.UI.Xaml.Controls.Button. The Xamarin.Forms.Button is an awkward beast, particularly on Windows, so basing a custom control on View is probably a better option.