Xamarin.Forms: Customize button style on hover in UWP - button

I have defined some style in App.xaml of the Xamarin Forms project. But that doesn't affect the button if you hover over it or press it. The font color changes here to black and a gray border around the button appears. Now I want to overwrite this style.
First try: add definition to App.xaml of the UWP project
<Application
x:Class="YourApp.UWP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:YourApp.UWP"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonPointerOverBackgroundThemeBrush" Color="#00FF00" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Result: no changes at all
Second try: overwrite PointOver visual state in App.xamlof UWP project
<Application
x:Class="YourApp.UWP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:YourApp.UWP"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<Style TargetType="Button" x:Key="HoverButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="#00FF00" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="#00FF00" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
Result: no changes at all, I think I have to applay the style (if I do this the button seems not to be here)
Third try: add complete button style and apply it
<Style TargetType="Button" x:Key="HoverButtonStyle">
<Setter Property="Background" Value="{ThemeResource ButtonBackgroundThemeBrush}" />
<Setter Property="Foreground" Value="{ThemeResource ButtonForegroundThemeBrush}"/>
<Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderThemeBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="12,4,12,4" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPointerOverBackgroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonPointerOverForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonPressedBackgroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonPressedForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonDisabledBackgroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonDisabledBorderThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonDisabledForegroundThemeBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="FocusVisualWhite"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0" />
<DoubleAnimation Storyboard.TargetName="FocusVisualBlack"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0" />
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused" />
<VisualState x:Name="PointerFocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="3">
<ContentPresenter x:Name="ContentPresenter"
Content="{TemplateBinding Content}"
ContentTransitions="{TemplateBinding ContentTransitions}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"/>
</Border>
<Rectangle x:Name="FocusVisualWhite"
IsHitTestVisible="False"
Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}"
StrokeEndLineCap="Square"
StrokeDashArray="1,1"
Opacity="0"
StrokeDashOffset="1.5" />
<Rectangle x:Name="FocusVisualBlack"
IsHitTestVisible="False"
Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}"
StrokeEndLineCap="Square"
StrokeDashArray="1,1"
Opacity="0"
StrokeDashOffset="0.5" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Custom renderer:
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (this.Element != null)
{
this.Control.Style = Windows.UI.Xaml.Application.Current.Resources["HoverButtonStyle"] as Windows.UI.Xaml.Style;
}
}
Result: style seems to be applied, but the background color I defined in Xamarin Forms doesn't take the full width of the button. Also the border color still isn't changed.
How is this done right?

Now I found out how this styling works. First you have to find the base UWP class (by holding Ctrl and clicking on the class name or by looking here). E.g. for Picker it is ComboBox. If you use Google you come to this page, where you find everything you need to know about overwriting the default layout of a ComboBox. For a Button it is this page and so on. So the solution is to have a App.xaml (UWP project) like this (take the color of your choice):
<Application
x:Class="YourApp.UWP.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:YourApp.UWP"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="SystemControlHighlightBaseMediumLowBrush" Color="White" />
<SolidColorBrush x:Key="SystemControlHighlightBaseHighBrush" Color="White" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
To apply a style only for some buttons, you have to do the following steps:
In App.xaml of your UWP project you need the following entry:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/DefaultButtonControlTemplate.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Here you register a style, which is in a separate file. I have a folder called Styles, where the file DefaultButtonControlTemplate.xaml is placed in. The content of the files taken from MSDN and looks like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp.UWP.ControlTemplates">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ColorsAndBrushes.xaml" />
</ResourceDictionary.MergedDictionaries>
<ControlTemplate x:Key="DefaultButtonControlTemplate" TargetType="Button">
<!-- here is the content of the file -->
</ControlTemplate>
</ResourceDictionary>
As you can see I'm referencing a common file, which contains all my colors (or brushes in UWP world).
Finally, you need a custom renderer like this:
public class DefaultButtonRenderer : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
this.Control.Template = Windows.UI.Xaml.Application.Current.Resources["DefaultButtonControlTemplate"] as Windows.UI.Xaml.Controls.ControlTemplate;
}
}
}

Found a way to keep it all within the UWP custom renderer, not having to worry about modifying anything else or if other button settings will conflict. In my case, I created a custom PillButton so obviously update your classes and colors or what not. If you don't see a corner radius on the button then it will be a normal button using the below.
[assembly: ExportRenderer(typeof(PillButton), typeof(PillButtonRenderer))]
namespace YourProject.UWP.Renderers
{
public class PillButtonRenderer : ButtonRenderer
{
public PillButton PillButtonElement => Element as PillButton;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Windows.UI.Xaml.Controls.Button button = Control;
Resources = (Windows.UI.Xaml.ResourceDictionary)XamlReader.Load(PillButtonStyleDictionary);
Resources["PillCornerRadius"] = PillButtonElement.CornerRadius;
Resources["PillBorderWidth"] = PillButtonElement.BorderWidth;
// if hover color not supplied, then hover color will be lighter version of background color, unless background color is transparent in which case it will be the border color
var hoverColor = PillButtonElement.UwpHoverColor != default(Color) ? PillButtonElement.UwpHoverColor
: (PillButtonElement.BackgroundColor == Color.Transparent
? PillButtonElement.BorderColor
: PillButtonElement.BackgroundColor.ChangeColorBrightness(0.15));
Resources["PillFillColorOnHover"] = new SolidColorBrush(hoverColor.ToUwp());
// if pressed color not supplied, then make it a darker shade of the hover color
var pressedColor = PillButtonElement.UwpPressedColor != default(Color) ? PillButtonElement.UwpPressedColor : hoverColor.ChangeColorBrightness(-0.09);
Resources["PillFillColorOnPressed"] = new SolidColorBrush(pressedColor.ToUwp());
// if text color on hover/press not supplied, then make it black or white depending on how dark the hover color is
var textColor = PillButtonElement.PressedTextColor != default(Color) ? PillButtonElement.PressedTextColor : hoverColor.BlackOrWhiteForegroundTextColor();
Resources["PillTextColorOnHoverOrPressed"] = new SolidColorBrush(textColor.ToUwp());
// set normal style
Resources["PillBackgroundColor"] = new SolidColorBrush(PillButtonElement.BackgroundColor.ToUwp());
Resources["PillTextColor"] = new SolidColorBrush(PillButtonElement.TextColor.ToUwp());
PillButtonElement.BackgroundColor = Color.Transparent; // hack
button.Style = Resources["PillButtonStyle"] as Windows.UI.Xaml.Style;
}
}
private const string PillButtonStyleDictionary = #"<ResourceDictionary
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
<x:Double x:Key=""PillCornerRadius"">0</x:Double>
<x:Double x:Key=""PillBorderWidth"">0</x:Double>
<SolidColorBrush
x:Key=""PillBackgroundColor""
Color=""Black"" />
<SolidColorBrush
x:Key=""PillTextColor""
Color=""Black"" />
<SolidColorBrush
x:Key=""PillFillColorOnHover""
Color=""Black"" />
<SolidColorBrush
x:Key=""PillFillColorOnPressed""
Color=""Black"" />
<SolidColorBrush
x:Key=""PillTextColorOnHoverOrPressed""
Color=""Black"" />
<Style
x:Key=""PillButtonStyle""
TargetType=""Button"">
<Setter
Property=""Background""
Value=""{ThemeResource SystemControlBackgroundBaseLowBrush}"" />
<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"">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name=""CommonStates"">
<VisualState x:Name=""Normal"">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName=""Pill""
Storyboard.TargetProperty=""Fill"">
<DiscreteObjectKeyFrame
KeyTime=""0""
Value=""{StaticResource PillBackgroundColor}"" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName=""ContentPresenter""
Storyboard.TargetProperty=""Foreground"">
<DiscreteObjectKeyFrame
KeyTime=""0""
Value=""{StaticResource PillTextColor}"" />
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName=""RootGrid"" />
</Storyboard>
</VisualState>
<VisualState x:Name=""PointerOver"">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName=""Pill""
Storyboard.TargetProperty=""Fill"">
<DiscreteObjectKeyFrame
KeyTime=""0""
Value=""{StaticResource PillFillColorOnHover}"" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName=""ContentPresenter""
Storyboard.TargetProperty=""Foreground"">
<DiscreteObjectKeyFrame
KeyTime=""0""
Value=""{StaticResource PillTextColorOnHoverOrPressed}"" />
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName=""RootGrid"" />
</Storyboard>
</VisualState>
<VisualState x:Name=""Pressed"">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName=""Pill""
Storyboard.TargetProperty=""Fill"">
<DiscreteObjectKeyFrame
KeyTime=""0""
Value=""{StaticResource PillFillColorOnPressed}"" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName=""ContentPresenter""
Storyboard.TargetProperty=""Foreground"">
<DiscreteObjectKeyFrame
KeyTime=""0""
Value=""{StaticResource PillTextColorOnHoverOrPressed}"" />
</ObjectAnimationUsingKeyFrames>
<PointerDownThemeAnimation Storyboard.TargetName=""RootGrid"" />
</Storyboard>
</VisualState>
<VisualState x:Name=""Disabled"">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName=""Pill""
Storyboard.TargetProperty=""Fill"">
<DiscreteObjectKeyFrame
KeyTime=""0""
Value=""{ThemeResource SystemControlBackgroundBaseLowBrush}"" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName=""ContentPresenter""
Storyboard.TargetProperty=""Foreground"">
<DiscreteObjectKeyFrame
KeyTime=""0""
Value=""{ThemeResource SystemControlDisabledBaseMediumLowBrush}"" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName=""Pill""
Storyboard.TargetProperty=""Stroke"">
<DiscreteObjectKeyFrame
KeyTime=""0""
Value=""{ThemeResource SystemControlDisabledTransparentBrush}"" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle
x:Name=""Pill""
RadiusX=""{StaticResource PillCornerRadius}""
RadiusY=""{StaticResource PillCornerRadius}""
Stroke=""{TemplateBinding BorderBrush}""
StrokeThickness=""{StaticResource PillBorderWidth}"" />
<ContentPresenter
x:Name=""ContentPresenter""
Padding=""{TemplateBinding Padding}""
HorizontalContentAlignment=""{TemplateBinding HorizontalContentAlignment}""
VerticalAlignment=""Center""
VerticalContentAlignment=""{TemplateBinding VerticalContentAlignment}""
AutomationProperties.AccessibilityView=""Raw""
Content=""{TemplateBinding Content}""
ContentTemplate=""{TemplateBinding ContentTemplate}""
ContentTransitions=""{TemplateBinding ContentTransitions}"" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>";
}
}
In case it comes up, here's the ToUwp color extension for converting from Xamarin Color to UWP Color that's being used in that code:
internal static class ColorExtensions
{
public static Color ToUwp(this Xamarin.Forms.Color color)
{
return Color.FromArgb((byte)(color.A * 255),
(byte)(color.R * 255),
(byte)(color.G * 255),
(byte)(color.B * 255));
}
}

Related

Xamarin Forms Entry opens only on double click (Android)

Currently I have a problem when I apply a style to an Entry it only opens on the second click. This only occurs when the applied Style uses the Visual State Manager with the VisualState Focused. If I remove the VisualState "Focused" the problem is solved.
Used style Code:
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="TextColor" Value="{StaticResource Color_Text_OnWhite}" />
<Setter Property="FontAttributes" Value="None"/>
</VisualState.Setters>
</VisualState>
<VisualState Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="{StaticResource Color_Text_OnWhite_Disabled}" />
<Setter Property="FontAttributes" Value="None"/>
</VisualState.Setters>
</VisualState>
<VisualState Name="Focused">
<VisualState.Setters>
<Setter Property="TextColor" Value="{StaticResource Color_Text_OnWhite}" />
<Setter Property="FontAttributes" Value="Bold"/>
</VisualState.Setters>
</VisualState>
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="TextColor" Value="{StaticResource Color_Text_OnWhite}" />
<Setter Property="FontAttributes" Value="Bold"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
Here is the Video to show the problem: https://vimeo.com/588825086
Is there a workaround available?
This issue is caused by the FontAttributes. Delete the code below would be okay.
<Setter Property="FontAttributes" Value="Bold"/>
The seetings of the Font like FontSize, FontAttributes with VisualState would make the Keyboard does not appear unless you tap twice.
The issue of FontSize is reported and has not solved yet. I would reported this FontAttributes as well. https://github.com/xamarin/Xamarin.Forms/issues/4573

does Xamarin.Forms Style support variable/parameter from applied target?

I have a complicated visual state and don't like to copy it to everywhere, so putting it in the ResourceDictionary
but some setter's value should be replaced by the real value from the target:
for example: the {Parameter1} and {Parameter1} are things I hope to replace.
<ResourceDictionary>
<Style x:Key="ToggleButton" TargetType="button:SfButton">
<Setter Property="ShowIcon" Value="True"/>
<Setter Property="IsCheckable" Value="True"/>
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList x:Name="CommonStates">
<VisualStateGroup>
<VisualState x:Name="Unchecked">
<VisualState.Setters>
<Setter Property="ImageSource" Value="{mb:ImageAsset Source={Parameter1} }" />
<Setter Property="BackgroundColor" Value="#3900" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Checked">
<VisualState.Setters>
<Setter Property="ImageSource" Value="{mb:ImageAsset Source={Parameter2} }" />
<Setter Property="BackgroundColor" Value="#6090" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ResourceDictionary>
but in the control's instantiation there's no way to pass these arguments:
<button:SfButton Style="{StaticResource ToggleButton, ??Parameter1=xxx?? }" Text="xx"/>
so is there anyway to achieve this?

Set DatePicker text color according to IsEnabled property

In one of my Xamarin.Forms apps I want to change the text color of a DatePicker according to the IsEnabled property.
I tried two known ways:
1) Using a style
In App.xaml:
<Style x:Key="DatePickerStyle" TargetType="DatePicker">
<Style.Triggers>
<Trigger TargetType="DatePicker" Property="IsEnabled" Value="True">
<Setter Property="TextColor" Value="Blue" />
</Trigger>
<Trigger TargetType="DatePicker" Property="IsEnabled" Value="False">
<Setter Property="TextColor" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
In View.xaml:
<DatePicker IsEnabled="{Binding IsEnabled}" Style="{StaticResource DatePickerStyle}" ... />
2) Adding the trigger in XAML
<ViewCell>
<DatePicker IsEnabled="{Binding IsEnabled}" ...>
<DatePicker.Triggers>
<Trigger TargetType="DatePicker" Property="IsEnabled" Value="True">
<Setter Property="TextColor" Value="Blue" />
</Trigger>
<Trigger TargetType="DatePicker" Property="IsEnabled" Value="False">
<Setter Property="TextColor" Value="Red" />
</Trigger>
</DatePicker.Triggers>
</DatePicker>
</ViewCell>
Both ways lead to a "System.InvalidOperationException: bindable not an instance of AssociatedType" exception.
Is it possible to change the text color of a picker with an applied style that contains a trigger at the IsEnabled property? Will a behavior be a better way to go?
I faced a similar issue with DatePicker and found no explanation on Xamarin forums or msdn. I have finally used the following workaround and it works
<Style TargetType="DatePicker">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList x:Name="CommonStates">
<VisualStateGroup>
<VisualState x:Name="Normal" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="TextColor" Value="LightGray" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
See also Visual State Manager.

Why is my ContentPresenter taking up more space than the content it's presenting

Now I don't know too much about control templates, but I'm trying to implement one following the article at: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/control-templates/creating
Question 1:
As far as I can tell, the ContentPresenter of a ControlTemplate simply displays exactly the content defined in the view that consumes the ControlTemplate, nothing more or less. Is my understanding correct?
Question 2 (I'll try my best to explain):
If the answer to (1) is yes, why is my ContentPresenter taking up more space than my content? See
My content is a StackLayout (green background) with Grid elements (pink background). Its dimension and position in the screenshot shown are exactly as I need. However, my ContentPresenter (red background) is expanding way beyond than its content (which is the green StackLayout).
If the answer to (1) is no, could the parent elements of the ContentPresenter (i.e, other elements in the ControlTemplate) be causing this?
Any help would be much appreciated. Thanks!
Edit 1 (Code I'm using):
The ContentPresenter in question belongs to a ControlTemplate targetting Xamarin.Forms.Platform.UWP.MasterDetailControl, as follows:
<Style TargetType="uwp:MasterDetailControl">
<Setter Property="ToolbarForeground" Value="{ThemeResource DefaultTextForegroundThemeBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="uwp:MasterDetailControl">
<SplitView PaneBackground="Transparent" x:Name="SplitView" IsPaneOpen="{Binding IsPaneOpen,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}" DisplayMode="Overlay">
<SplitView.Pane>
<Grid HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Visibility="{TemplateBinding MasterToolbarVisibility}">
<Button Name="PaneTogglePane" Style="{StaticResource MenuButton}"/>
</StackPanel>
<controls:DropShadowPanel Grid.Row="1" Style="{StaticResource MasterMenuDropShadow}" Margin="12.5,0,0,0">
<StackPanel Background="Yellow">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="Assets\master_menu_pointer.png" />
<StackPanel Grid.Column="1" />
</Grid>
<ContentPresenter Padding="0"
Background="Red"
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Master}"
Margin="0,-1,0,0" />
</StackPanel>
</controls:DropShadowPanel>
</Grid>
</SplitView.Pane>
Master (in Path=Master above) derives from a ContentPage with Content defined in its code behind as follows:
Content = new StackLayout
{
Children = {_firstPinkChild, _secondPinkChild},
Padding = 15,
Margin = 0,
Orientation = StackOrientation.Horizontal,
BackgroundColor = Color.Green,
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.Start
};
Edit 2 (Some more styles being used):
<Style TargetType="controls:DropShadowPanel" x:Key="MasterMenuDropShadow">
<Setter Property="Color" Value="#595959"/>
<Setter Property="OffsetX" Value="-2"/>
<Setter Property="OffsetY" Value="0"/>
<Setter Property="BlurRadius" Value="50"/>
<Setter Property="ShadowOpacity" Value=".7"/>
</Style>
<Style TargetType="Button" x:Key="MenuButton">
<Setter Property="Width" Value="{StaticResource AppBarThemeCompactHeight}" />
<Setter Property="Height" Value="{StaticResource AppBarThemeCompactHeight}" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Margin="0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="icon">
<DiscreteObjectKeyFrame KeyTime="0" Value="Assets\hamburger_onhover.icon.png"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="icon">
<DiscreteObjectKeyFrame KeyTime="0" Value="Assets\hamburger.icon.png"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Image Name="icon" Source="Assets\hamburger.icon.png" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
From official document,
The ContentView.Content property is set to a StackLayout that defines the content to be displayed on the ContentPage. This content will be displayed by the ContentPresenter contained in the TealTemplate.
For better understand please look the follow screenshot. The display air of ContentPresenter is the red block that placed in the row 2, column 0-1.
Your content will be displayed in the ContentPresenter.
<StackLayout BackgroundColor="Green">
<Label Text="Welcome to the app!" HorizontalOptions="Center" />
<Button Text="Change Theme" />
</StackLayout>
So, the answer of the first question is true. For your second question, you need to post your xaml code. Maybe you wrongly define the display area of ContentPresenter.

Make button turns background white when press

http://2.bp.blogspot.com/-bQZRfy4g4t0/TWK05e_Bx9I/AAAAAAAAAEY/nym2bRu-RjI/s1600/5.bmp
How do I make my button that contains image change to white background when being press?
On default, when I press my button it doesn't show the image in the button and change to phone accent color.
Here's the XAML code for the button :
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="Img">
<DiscreteObjectKeyFrame KeyTime="0" Value="Assets/appbar.control.play.png" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
<DiscreteObjectKeyFrame KeyTime="0" Value="Black"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
what you need to do is create a button template that modifies the pressed visual state.
See if this or this SO answers helps you, both links have the Pressed visual state code.
You will need to change the Pressed visual state to:
(In this case background is changed to Red when the button is pressed)
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="Img">
//Set you image path like this
<DiscreteObjectKeyFrame KeyTime="0" Value="Assets/..." />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="Red"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="Red"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>

Resources