Apply style to control in custom renderer - xamarin

I want to apply a style to a control. This is the style
<Application.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="BackgroundColor" Color="Yellow" />
<Style TargetType="Button" x:Name="myNewButtonStyle">
<Setter Property="Background" Value="{StaticResource BackgroundColor}" />
</Style>
</ResourceDictionary>
</Application.Resources>
, which can be found in App.xaml (UWP project). And here is the custom renderer:
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (this.Element != null)
{
var style = Windows.UI.Xaml.Application.Current.Resources["myNewButtonStyle"] as Windows.UI.Xaml.Style;
this.Control.Style = style;
}
}
The idea is based on this answer. But the style isn't applied. Setting the background color in code does work:
this.Control.BackgroundColor = new SolidColorBrush(Windows.UI.Colors.Yellow);
How can I apply a style to a control in a custom renderer?

I've filled a bug report. It should be fixed in one of the upcoming releases (> XF 2.3.3.166-pre4).

Related

UWP Toolkit DataGrid Cells Padding/Margin

I'm struggling to remove/clear the padding/margin of DataGrid cells.
Appreciate if anyone can help how to remove the padding/margin. I'm using DataGridTextColumn because I need the TextBox for editing the value. I have manage to remove the padding/margin for the TextBox by setting the style for EditingElementStyle, that is;
<Style x:Key="tbEntry" TargetType="TextBox">
<Setter Property="Padding" Value="5" />
<Setter Property="Margin" Value="0" />
<Setter Property="Width" Value="45" />
</Style>
However, I cannot change the styles padding/margin for the cells after the TextBox unfocus. I have try setting on CellStyle or ElementStye of DataGridTextColumn with no luck.
What about this example?
xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls"
...
<toolkit:DataGridTemplateColumn Header="Lng" Tag="Lng">
<toolkit:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Lng, Mode=OneWay}" Margin="1,1,1,1" Padding="1,1,1,1">
</TextBlock>
</DataTemplate>
</toolkit:DataGridTemplateColumn.CellTemplate>
</toolkit:DataGridTemplateColumn>
Riza, you can control the margin used in non-editing mode by using a custom text column instead of the DataGridTextColumn. Use this one:
public class MyDataGridTextColumn : DataGridTextColumn
{
public MyDataGridTextColumn()
{
}
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
TextBlock textBlock = base.GenerateElement(cell, dataItem) as TextBlock;
textBlock.Margin = new Thickness(2, 0, 2, 0);
return textBlock;
}
}
...and adjust the margin as you wish. Thanks.

How can I set the text color and style of an elements and all its children in C#

I have this code:
<StackLayout x:Name="OuterSL" >
<StackLayout.Resources>
<Style TargetType="Label">
<Setter Property="TextColor" Value="Red" />
<Setter Property="Style" Value="{StaticResource HelpDetail}" />
</Style>
</StackLayout.Resources>
<Label Text="Overview" />
<Grid >
<Grid.Resources>
<Style TargetType="Label">
<Setter Property="TextColor" Value="Red" />
<Setter Property="Style" Value="{StaticResource HelpDetail}" />
</Style>
</Grid.Resources>
Can someone tell me how I can do the setting of the TextColor and the Style in the backend C#. In particular I would like to do this for all the children here. So I would need to find all of the Grid's that are part of the StackLayout and set the Text and Style for them also. Note that this for example I just gave a snippet of the code. In the real code I have many Grids inside the StackLayout and I am setting the Resources in them all. Also I don't want to set at the page content level. Just everything inside the StackLayout named OuterSL.
Each Layout control (Grid/Stacklayout/...) has a Children property (a list of Views) and those children can be also be layout containers (or not), so if you recursively descend the view hierarchy you can assign the styles and colors for all the view elements as needed...
This should help you get started.
void SetStyles(IList<View> children, Style style)
{
foreach (var child in children)
{
switch (child)
{
case StackLayout s:
child.Style = style;
if (s.Children.Count > 0)
SetStyles(s.Children, style);
break;
case Grid g:
if (g.Children.Count > 0)
SetStyles(g.Children, style);
break;
case Entry e:
e.TextColor = Color.Red;
break;
case Label l:
l.TextColor = Color.Green;
break;
~~~
}
}
Just call it like:
if (Application.Current.Resources.TryGetValue("SomeStackLayoutStyle", out object style))
{
SetStyles(someStackLayout.Children, Style(style));
}

Text Style not applied when Xamarin Forms is initialized

I have a UWP app and try out Embedded Xamarin Forms. The embedding itself works so far. But I noticed that certain TextStyles do no longer work after I initialized Forms.
Without Forms:
After Forms.Init:
The only difference is this Line in the App.xaml.cs:
Xamarin.Forms.Forms.Init(e);
The Code of the TextBlock is:
<TextBlock x:Name="TitlePage"
Text="Hello"
Style="{StaticResource PageTitleStyle}" />
And the style:
<Style x:Key="PageTitleStyle"
TargetType="TextBlock">
<Setter Property="VerticalAlignment"
Value="Center" />
<Setter Property="FontWeight"
Value="SemiLight" />
<Setter Property="FontSize"
Value="{StaticResource LargeFontSize}" />
<Setter Property="TextTrimming"
Value="CharacterEllipsis" />
<Setter Property="TextWrapping"
Value="NoWrap" />
<Setter Property="Margin"
Value="{StaticResource PageTitleMargin}" />
</Style>
I created a minimal example which you can find here: https://github.com/NPadrutt/EmbeddedFormsTest
Versions:
VS 15.5.2
Xamarin.Forms 2.5.0.121934
Microsoft.NETCore.UniversalWindowsPlatform 6.0.5
When you execute Xamarin.Forms.Forms.Init(e);, it will load the ResourceDictionary which defined in Xamarin. So that after this code line invoked, the text may show the style defined in Xamarin Forms, not the style you defined in UWP. Details you can check the code snippet of Init method.
Updated:
The Init method merge the style by this code line
return new Windows.UI.Xaml.ResourceDictionary {
Source = new Uri("ms-appx:///Xamarin.Forms.Platform.UAP/Resources.xbf")
And you will find the following style in Resource.xaml in Xamarin.
<Style x:Key="PageTitleStyle" TargetType="TextBlock">
<Setter Property="FontWeight" Value="Bold" />
</Style>
Which has same x:key (PageTitleStyle) as you defined so that your style will be override. Just change the x:key of your style it will not be influenced by the Xamarin resources,for example PageTitleStyle2.
If you want to use the style you defined in UWP app for the Xamarin Forms, you could use Custom Renderers. TextBlock is the native control for UWP, the correspondent control in Xamarin Forms is Label. Details please see Renderer Base Classes and Native Controls. You should have a Label control in Xamarin Forms and create a custom renderer for Label and set the style with target type is TextBlock in UWP. For example:
public class MyLabelRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
Control.Style= (Windows.UI.Xaml.Style)App.Current.Resources["PageTitleStyle"];
}
}
For more samples you could reference this.

Change Xamarin Forms default colour (grey) to black?

By default, it seems that the background is white and the labels are grey. This looks bad. I would change the labels' colour to complete black.
But I do not want to set the TextColor individually. There must be a way to change the default label color at once. I looked into the shared module, but I cannot find anything. The sytles.xml in the Android project does not have the grey colour. Where can I find it?
You can do this many ways but simplest way is using custom control
public class MyLabel : Label
{
public MyLabel ()
{
BackgroundColor = Color.Gray;
}
}
You can use using this :
<MyLabel Text="This is testing" />
Re: https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/introduction/
OR
Set style in App.xaml
<Application.Resources>
<ResourceDictionary>
<Style TargetType="Label">
<Setter Property="TextColor" Value="Gray" />
</Style>
</ResourceDictionary>
</Application.Resources>
If you want to change TextColor of all label then you can do it from implicit style like this:
<Style TargetType="Label">
<Setter Property="TextColor" Value="Black" />
</Style>
And add this to resource dictionary of App.xaml

Custom Renderer: Custom Renderer for rounded buttons

I am developing a cross-platform app using PCL Xamarin Forms Project. My app will run on ios, android, windows 10 and windows 8.1 desktops.
I want to make a custom renderer for button control in xamarin forms in which I can specify following properties from xaml page and from code behind also-
Border Color
Border Width
Border Radius
Background Color
Text Color
Text font size, color, attribute like bold.
Height and Width of Button
I have tried the normal button control of xamarin forms but in that border radius does not work in android and on hover button color changes in windows 10.
So how can I achieve this?
I using these properties on my app and for me works fine.
I am using these properties with "Styles".
Example:
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="BackgroundColor" Value="{DynamicResource Snow}"/>
<Setter Property="TextColor" Value="{DynamicResource LightBlue}" />
<Setter Property="BorderColor" Value="{DynamicResource LightBlue}"/>
<Setter Property="BorderRadius" Value="15"/>
<Setter Property="BorderWidth" Value="1"/>
<Setter Property="FontAttributes" Value="Bold" />
</Style>
My Button:
<Button Text="Login" Command="{Binding LoginCommand}" Style="{DynamicResource buttonStyle}" />
Xamarin Styles
In Android the RadiusProperty stops working only with AppCompat its a known issue
AppCompat
If you want to use a normal button and AppCompat at the same time you will need to inherit from Button and register a CustomRenderer.
[assembly: ExportRenderer(typeof(RoundButton), typeof(RoundButtonRenderer))]
namespace Project.Droid.Renderers
{
public class RoundButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
{
ButtonDrawable _backgroundDrawable;
Drawable _defaultDrawable;
bool _drawableEnabled;
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_backgroundDrawable != null)
{
_backgroundDrawable.Dispose();
_backgroundDrawable = null;
}
}
base.Dispose(disposing);
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if (e.OldElement != null && _drawableEnabled)
{
_drawableEnabled = false;
_backgroundDrawable.Reset();
_backgroundDrawable = null;
}
UpdateDrawable();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (_drawableEnabled &&
(e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName || e.PropertyName == Xamarin.Forms.Button.BorderColorProperty.PropertyName || e.PropertyName == Xamarin.Forms.Button.BorderRadiusProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Button.BorderWidthProperty.PropertyName))
{
_backgroundDrawable.Reset();
Control.Invalidate();
}
base.OnElementPropertyChanged(sender, e);
}
private void UpdateDrawable()
{
if (Element.BackgroundColor == Color.Default)
{
if (!_drawableEnabled)
return;
if (_defaultDrawable != null)
Control.SetBackground(_defaultDrawable);
_drawableEnabled = false;
}
else
{
if (_backgroundDrawable == null)
_backgroundDrawable = new ButtonDrawable();
_backgroundDrawable.Button = Element;
if (_drawableEnabled)
return;
if (_defaultDrawable == null)
_defaultDrawable = Control.Background;
Control.SetBackground(_backgroundDrawable.GetDrawable());
_drawableEnabled = true;
}
Control.Invalidate();
}
}
public class ButtonDrawable : IDisposable
{
object _backgroundDrawable;
PropertyInfo ButtonProperty;
public Xamarin.Forms.Button Button
{
get
{
return (Xamarin.Forms.Button)ButtonProperty.GetMethod.Invoke(_backgroundDrawable, null);
}
set
{
ButtonProperty.SetMethod.Invoke(_backgroundDrawable, new object[] { value });
}
}
public ButtonDrawable()
{
_backgroundDrawable = typeof(Xamarin.Forms.Platform.Android.ButtonRenderer).Assembly.CreateInstance("Xamarin.Forms.Platform.Android.ButtonDrawable");
this.ResetMethod = _backgroundDrawable.GetType().GetMethod("Reset", BindingFlags.Instance | BindingFlags.Public);
this.DisposeMethod = _backgroundDrawable.GetType().GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public);
this.ButtonProperty = _backgroundDrawable.GetType().GetProperty("Button", BindingFlags.Instance | BindingFlags.Public);
}
MethodInfo ResetMethod;
public void Reset()
{
ResetMethod.Invoke(_backgroundDrawable, null);
}
MethodInfo DisposeMethod;
public void Dispose()
{
DisposeMethod.Invoke(_backgroundDrawable, null);
}
public Android.Graphics.Drawables.Drawable GetDrawable()
{
return _backgroundDrawable as Android.Graphics.Drawables.Drawable;
}
}
}
Without AppCompat
if you want to remove AppCompat you must do two things
Your MainActivity must inherit now from global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
and your style usually in resources/values/styles.xml must inherit from a non-AppCompat style like android:Theme.Material
<resources>
<!-- inherit from the material theme -->
<style name="AppTheme" parent="android:Theme.Material">
<!-- Main theme colors -->
<!-- your app branding color for the app bar -->
<item name="android:colorPrimary">#color/primary</item>
<!-- darker variant for the status bar and contextual app bars -->
<item name="android:colorPrimaryDark">#color/primary_dark</item>
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">#color/accent</item>
</style>
</resources>
Create a style in Content Page resource and and add this style in button.
CornerRadius is must be half of HeightRequest and WidthRequest.
This is for Xamarin.Forms >= 3.4. Now BorderRadius convert into CornerRadius.
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="myRoundbutton" TargetType="Button">
<Setter Property="BackgroundColor" Value="Green"/>
<Setter Property="TextColor" Value="White" />
<Setter Property="BorderColor" Value="Blue"/>
<Setter Property="CornerRadius" Value="35"/>
<Setter Property="HeightRequest" Value="70" />
<Setter Property="WidthRequest" Value="70"/>
<Setter Property="BorderWidth" Value="2"/>
<Setter Property="FontAttributes" Value="Bold" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout HorizontalOptions="Fill"
VerticalOptions="Fill">
<Button Image="myBtn3.png"
Command="{Binding LoginCommand}"
Style="{DynamicResource myRoundbutton}" />
</StackLayout>
</ContentPage.Content>

Resources