Bug 60605 - Specified cast is not valid when setting a Style
Summary: Specified cast is not valid when setting a Style
Status: RESOLVED ANSWERED
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 2.4.0
Hardware: PC Windows
: --- normal
Target Milestone: ---
Assignee: Stephane Delcroix
URL:
Depends on:
Blocks:
 
Reported: 2017-11-09 22:23 UTC by KTM450SXF
Modified: 2017-11-13 14:37 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED ANSWERED

Description KTM450SXF 2017-11-09 22:23:48 UTC
I have a StackLayout that contains a single element, a Label.  I need to set the BackgroundColor of the StackLayout and the TextColor of the Label and those two properties need to change dynamically.  I created a single Style and bound the Style of the StackLayout to a property of type Style.  That markup looks like this:

<StackLayout Grid.Row="1" Grid.Column="1" Style="{ Binding DIARY_DATE_VALID_STYLE }" WidthRequest="110" >
   <Label Text="{Binding DIARY_DATE, StringFormat='{0:MM/dd/yyyy}' }" HorizontalTextAlignment="Start"/>
</StackLayout>

In App.cs, I create the style like this:

 Style invalid = new Style(typeof(VisualElement));
Setter invalidLabelBackgroundColor = new Setter();
invalidLabelBackgroundColor.Property = VisualElement.BackgroundColorProperty;
invalidLabelBackgroundColor.Value = new Color(255, 0, 0);
invalid.Setters.Add(invalidLabelBackgroundColor);
Setter invalidLabelColor = new Setter();
invalidLabelColor.Property = Label.TextColorProperty;
invalidLabelColor.Value = Color.White;
invalid.Setters.Add(invalidLabelColor);
Current.Resources.Add("invalid", invalid);

My original thinking was that it would function like HTML - I'd apply the style to the containing object and that would be inherited by child objects.  That didn't work with the text color so I decided to circle back around to it at some point and moved on.

Well, I updated to 2.4.0.38779 and my app completely broke.  The stack trace is at the bottom of this post.  My hunch is that prior versions of Forms simply ignored Style Setters not applicable to the control in question.  StackLayout doesn't have a TextColorProperty so Forms ignored it, not trying to apply it.  With this update, it is trying to apply it and crashing in an incredibly unhelpful manner.

My preference would be for you to set up a child object inheritance system.  Barring that, the least you can do is provide some form of helpful message, which this is not:

Specified cast is not valid.
at Xamarin.Forms.TextElement.OnTextColorPropertyChanged (Xamarin.Forms.BindableObject bindable, System.Object oldValue, System.Object newValue) [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Core\TextElement.cs:11 
  at Xamarin.Forms.BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindableObject+BindablePropertyContext context, System.Object value, System.Boolean currentlyApplying, Xamarin.Forms.Internals.SetValueFlags attributes, System.Boolean silent) [0x00108] in D:\agent\_work\1\s\Xamarin.Forms.Core\BindableObject.cs:596 
  at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes) [0x0015b] in D:\agent\_work\1\s\Xamarin.Forms.Core\BindableObject.cs:390 
  at Xamarin.Forms.BindableObject.SetValue (Xamarin.Forms.BindableProperty property, System.Object value, System.Boolean fromStyle, System.Boolean checkAccess) [0x0005f] in D:\agent\_work\1\s\Xamarin.Forms.Core\BindableObject.cs:543 
  at Xamarin.Forms.BindableObject.SetValue (Xamarin.Forms.BindableProperty property, System.Object value, System.Boolean fromStyle) [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Core\BindableObject.cs:324 
  at Xamarin.Forms.Setter.Apply (Xamarin.Forms.BindableObject target, System.Boolean fromStyle) [0x00097] in D:\agent\_work\1\s\Xamarin.Forms.Core\Setter.cs:60 
  at Xamarin.Forms.Style.ApplyCore (Xamarin.Forms.BindableObject bindable, Xamarin.Forms.Style basedOn) [0x0001e] in D:\agent\_work\1\s\Xamarin.Forms.Core\Style.cs:135 
  at Xamarin.Forms.Style.Xamarin.Forms.IStyle.Apply (Xamarin.Forms.BindableObject bindable) [0x0002b] in D:\agent\_work\1\s\Xamarin.Forms.Core\Style.cs:98 
  at Xamarin.Forms.VisualElement+MergedStyle.SetStyle (Xamarin.Forms.IStyle implicitStyle, System.Collections.Generic.IList`1[T] classStyles, Xamarin.Forms.IStyle style) [0x00156] in D:\agent\_work\1\s\Xamarin.Forms.Core\MergedStyle.cs:163 
  at Xamarin.Forms.VisualElement+MergedStyle.set_Style (Xamarin.Forms.IStyle value) [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Core\MergedStyle.cs:39 
  at Xamarin.Forms.VisualElement+<>c.<.cctor>b__213_6 (Xamarin.Forms.BindableObject bindable, System.Object oldvalue, System.Object newvalue) [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Core\VisualElement.cs:80 
  at Xamarin.Forms.BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindableObject+BindablePropertyContext context, System.Object value, System.Boolean currentlyApplying, Xamarin.Forms.Internals.SetValueFlags attributes, System.Boolean silent) [0x00108] in D:\agent\_work\1\s\Xamarin.Forms.Core\BindableObject.cs:596 
  at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes) [0x0015b] in D:\agent\_work\1\s\Xamarin.Forms.Core\BindableObject.cs:390 
  at Xamarin.Forms.BindableObject.SetValue (Xamarin.Forms.BindableProperty property, System.Object value, System.Boolean fromStyle, System.Boolean checkAccess) [0x0005f] in D:\agent\_work\1\s\Xamarin.Forms.Core\BindableObject.cs:543 
  at Xamarin.Forms.BindableObject.SetValue (Xamarin.Forms.BindableProperty property, System.Object value) [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Core\BindableObject.cs:83 
  at Xamarin.Forms.VisualElement.set_Style (Xamarin.Forms.Style value) [0x00000] in D:\agent\_work\1\s\Xamarin.Forms.Core\VisualElement.cs:250 
  at Fieldbook.Controls.DatePickerFB.propertyChanged (System.Object sender, System.ComponentModel.PropertyChangedEventArgs e) [0x00017] in D:\Code\Fieldbook\Fieldbook\Fieldbook\Controls\DatePickerFB.xaml.cs:172
Comment 2 Paul DiPietro [MSFT] 2017-11-09 22:39:49 UTC
If you happen to have a small reproduction we can simply run to aid investigation, that's always helpful as well.
Comment 3 KTM450SXF 2017-11-09 22:42:52 UTC
It's a relatively straightforward bug.  You'll get it if you set up a View containing the markup I included and set up the Style as I did and then Bind it to a Style Property that returns the style.  

If you guys run into trouble reproducing it, let me know.  I doubt you will.
Comment 4 Stephane Delcroix 2017-11-13 11:25:09 UTC
you can reproduce this by doing

   stackLayout.SetValue(Label.TextColorProperty, Color.White)

or the XAML equiv

    <StackLayout Label.TextColor="White" />

Both will fail, as they are expected to. It's not because XF doesn't distinguish attached bindable properties from 'normal' bindable properties that one can be use for the other.

Xamarin.Forms Styles require a TargetType argument, and you should make sure the properties in the Setters applies on that type.

You are only able to do this because you define your ResourceDictionary in code. This Xaml "equivalent" would have been invalid

<ResourceDictionary>
    <Style x:Key="invalid" TargetType="VisualElement">
        <Setter Property="TextColor" Value="White" />
    </Style>
</ResourceDictionary>

and the parsing of it would have failed at compile time or runtime (depending if you use XamlC or not)

(to be complete, the style could be parsed if the property was set to `Property="Label.TextColor"`, but we're back to the beginning of this post, abusing a bindable property as an attached one)
Comment 5 KTM450SXF 2017-11-13 13:06:10 UTC
I understand your explanation and on principle, I agree that it should fail, given XF's chosen system of applying styles.

However, it did not fail prior to updating XF, as I explained.  Why the change?  

Moreover, I offer a few criticisms.  Do with them what you will:
1.  I would expect/hope for a slightly more helpful message.
2.  An inherited style system would be nice.  If I add a TextColor setter to a style and set that style as a StackLayout's style, it would be nice if all child objects that have a TextColor get that setter.  Yes, such a system would be challenging to implement, but also very useful.
3.  Why am I able to do something in code that I cannot do in XAML?

No response is necessary; do with these criticisms as you will.
Comment 6 Stephane Delcroix 2017-11-13 14:37:05 UTC
1. agree
2. we're working on CSS support
3. see the comment between () at the end. you can do it in xaml