xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.62k stars 1.87k forks source link

[Bug] HotReload does not reload CSS from linked embedded files #10299

Open tomeverin opened 4 years ago

tomeverin commented 4 years ago

Description

When updating xaml via hot reload, any CSS styling that is a result of linked style sheets (embedded .css resource) is lost.

Steps to Reproduce

  1. Any xamarin forms project
  2. Style some visual elements by linking to an embedded .css
  3. Link it into XAML at ContentPage.Resources with: <StyleSheet Source="/Embedded/globalstyle.css" />

Expected Behavior

On hot reload, the linked styles are still applied

Actual Behavior

Linked style sheet styles are no longer applied until next deploy and run

Basic Information

VS bug #1101668

ChrisMissal commented 3 years ago

Does anybody know if there any current workarounds for this?

chucker commented 3 years ago

Does anybody know if there any current workarounds for this?

Sort of.

Let's say you use an app-wide stylesheet and currently apply it in the App.xaml as follows:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourProjectName.App" PageAppearing="Application_PageAppearing">
    <Application.Resources>
        <StyleSheet Source="AppStylesheet.css" x:Key="Stylesheet" />
    </Application.Resources>
</Application>

Remove that resource. Instead, in your App.xaml.cs's App() constructor, underneath MainPage = new MainPage() (or similar), add:

            new System.Threading.Timer(_ =>
            {
                Dispatcher.BeginInvokeOnMainThread(() =>
                {
                    var prop = this.Resources.GetType().GetProperty("StyleSheets", BindingFlags.NonPublic | BindingFlags.Instance);
                    prop.SetValue(this.Resources, null);

                    using (var sr = new StreamReader("../../../../../../YourProjectName/AppStylesheet.css"))
                        this.Resources.Add(Xamarin.Forms.StyleSheets.StyleSheet.FromReader(sr));
                });
            }, null, 1_000, 1_000);

(I'll leave figuring out the correct relative path to the style sheet as an exercise to the reader.)

What this does, once a second, is two things:

If you now open that style sheet in the IDE and, say, change something like a background-color property, you'll see an effect within at most a second. (Tested on macOS and iOS targets.) Other properties like font-size I've found to not work reliably, but I think this is a problem not specific to this bug.

The above works because, if StyleSheets is null, that initializes the internals of style sheet management. There are hints that this was supposed to be more dynamic; e.g. there's a collection changed event handler (but it doesn't seem to get attached to anything).