OnPlatform resource in code behind

My application resources:

<Application.Resources>
        <ResourceDictionary>
            <OnPlatform x:Key="FontFamilyRegular" x:TypeArguments="x:String">
                <On Platform="iOS">.SFUIText</On>
                <On Platform="Android">sans-serif</On>
                <On Platform="Windows">Segoe UI</On>
            </OnPlatform>
...

This works well:

<Label x:Name="MessageText" FontFamily="{StaticResource FontFamilyRegular}" FontSize="15" />

How can I specify font family value in c# like:

MessageText.FontFamily = (???)Application.Current.Resources["FontFamilyRegular"];
Tagged:

Best Answers

  • mjromkamjromka ✭✭
    edited October 2018 Accepted Answer

    Now I understand what happened. This returns correct string (e.g. ".SFUIText") in Visual Studio Expression evaluator

    (string)Application.Current.Resources["FontFamilyRegular"]
    

    But this code line won't set an appropriate property of the label to ".SFUIText", but reset it to null:

    MessageText.FontFamily = (string)Application.Current.Resources["FontFamilyRegular"];
    

    However if I put the line above to the Expression evaluator it will correctly set the property. Looks like Visual Studio (Community 2017 for Mac) or Xamarin (v.3.2.0) bug. I'll have to rollback to my workaround:

    MessageText.FontFamily = (string)((OnPlatform<string>)Application.Current.Resources["FontFamilyMedium"])
        .Platforms.FirstOrDefault(p => p.Platform[0] == Device.RuntimePlatform)?.Value;
    

    (facepalm)

  • SteveShaw.5557SteveShaw.5557 US ✭✭✭
    edited November 2018 Accepted Answer

    @mjromka - that isn't a bug. If you write code var value = Application.Current.Resources["FontFamilyRegular"];, and hover over var, you'll see that the return type of a resource is object.

    For the "implicit conversion" from OnPlatform<string> to string to occur, one must have an object whose type is known at compile-time to be OnPlatform<string>.

    The syntax that works in your case is:

    MessageText.FontFamily = (OnPlatform<string>)Application.Current.Resources["FontFamilyRegular"];
    

    That is, you must do an explicit conversion from object to the type that you "know" is there, OnPlatform<string>.
    The compiler can then generate code to do the implicit conversion from OnPlatform<string> to string.

    I assume this is by design for performance reasons: it would be slow at run-time, when given an object, for the code to dynamically look at the actual type, and the type that is desired, then to search for an implicit conversion between those types. So you have to make sure there is enough information at compile-time for the conversion to be found, and placed in the generated code.

    (I guess Visual Studio Expression evaluator is willing to do more work, so it examines the actual type of the object, and does the magic for you. Since it only needs to evaluate one expression at a time, it doesn't have to be super fast.)

Answers

  • seanydaseanyda GBMember ✭✭✭✭✭

    Here is an example of me using C# TargetPlatform in UI.

    new Button { Text= "Test", FontSize = Device.RuntimePlatform == Device.iOS ? 14 : 12, CommandParameter = 1, BackgroundColor = Color.FromRgb(0, 73, 144), HorizontalOptions = LayoutOptions.End, WidthRequest = 50, HeightRequest = Device.RuntimePlatform == Device.iOS ? 30 : 40, VerticalOptions = LayoutOptions.Start, TextColor = Color.White }
    
  • mjromkamjromka Member ✭✭

    Thank you @JoeManke , didn't pay attention that casting object of type OnPlatform to string will give me desired result. I tried .ToString() and it didn't work and it confused me.

  • mjromkamjromka Member ✭✭
    edited October 2018 Accepted Answer

    Now I understand what happened. This returns correct string (e.g. ".SFUIText") in Visual Studio Expression evaluator

    (string)Application.Current.Resources["FontFamilyRegular"]
    

    But this code line won't set an appropriate property of the label to ".SFUIText", but reset it to null:

    MessageText.FontFamily = (string)Application.Current.Resources["FontFamilyRegular"];
    

    However if I put the line above to the Expression evaluator it will correctly set the property. Looks like Visual Studio (Community 2017 for Mac) or Xamarin (v.3.2.0) bug. I'll have to rollback to my workaround:

    MessageText.FontFamily = (string)((OnPlatform<string>)Application.Current.Resources["FontFamilyMedium"])
        .Platforms.FirstOrDefault(p => p.Platform[0] == Device.RuntimePlatform)?.Value;
    

    (facepalm)

  • SteveShaw.5557SteveShaw.5557 USMember ✭✭✭
    edited November 2018 Accepted Answer

    @mjromka - that isn't a bug. If you write code var value = Application.Current.Resources["FontFamilyRegular"];, and hover over var, you'll see that the return type of a resource is object.

    For the "implicit conversion" from OnPlatform<string> to string to occur, one must have an object whose type is known at compile-time to be OnPlatform<string>.

    The syntax that works in your case is:

    MessageText.FontFamily = (OnPlatform<string>)Application.Current.Resources["FontFamilyRegular"];
    

    That is, you must do an explicit conversion from object to the type that you "know" is there, OnPlatform<string>.
    The compiler can then generate code to do the implicit conversion from OnPlatform<string> to string.

    I assume this is by design for performance reasons: it would be slow at run-time, when given an object, for the code to dynamically look at the actual type, and the type that is desired, then to search for an implicit conversion between those types. So you have to make sure there is enough information at compile-time for the conversion to be found, and placed in the generated code.

    (I guess Visual Studio Expression evaluator is willing to do more work, so it examines the actual type of the object, and does the magic for you. Since it only needs to evaluate one expression at a time, it doesn't have to be super fast.)

Sign In or Register to comment.