Dreamescaper / BlazorBindings.Maui

MAUI Blazor Bindings - Build native and hybrid MAUI apps with Blazor
MIT License
242 stars 16 forks source link

How to use style in BlazorBindings #119

Open shugaoye opened 1 year ago

shugaoye commented 1 year ago

I cannot find an example about CSS style. Can you provide an example to use CSS style? Is it possible to use XAML style in Resources/Styles/Styles.xaml? If not, how can we translate it to CSS?

If I add a css like below, I got an exception.

<StyleSheet Resource="mystyle.css" Assembly="GetType().Assembly"></StyleSheet>
<TabbedPage>

    <ContentPage Title="Todo">
        <StackLayout>
            <Label FontSize="20" TextColor="Colors.Crimson" Text="Todo Items" HorizontalTextAlignment="TextAlignment.Center" />
            <TodoList />
        </StackLayout>
    </ContentPage>

    <ContentPage Title="Counter">
        <Counter />
    </ContentPage>

    <ContentPage Title="About">
        <About />
    </ContentPage>

</TabbedPage>

It cannot work and I found this exception.

System.ArgumentException: 'parentElement (Parameter 'Expected parent to be of type 'Microsoft.Maui.Controls.VisualElement' but it is of type 'BlazorBindings.Maui.BlazorBindingsApplication`1[[BlazorBindingsToDo.TodoApp, BlazorBindingsToDo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.')'
Dreamescaper commented 1 year ago

I haven't added anything to have a better experience with XAML styles yet, but you can use those. You can add something like that to your App constructor (if you're looking to apply them globally):

public class App : BlazorBindingsApplication<AppShell>
{
    public App(IServiceProvider services) : base(services)
    {
        var stylesType = typeof(App).Assembly.GetCustomAttributes<XamlResourceIdAttribute>()
            .First(a => a.Path == "Resources/Styles/Styles.xaml")
            .Type;

        var stylesResources = (ResourceDictionary)Activator.CreateInstance(stylesType);

        Resources.Add(stylesResources);
    }
}
Dreamescaper commented 1 year ago

If you want, you can define such styles with C# instead of XAML (although it looks a bit ugly to my taste). Here's the example:

    public static class Styles
    {
        public static void ApplyTo(ResourceDictionary dictionary)
        {
            dictionary.Add(_pageTitleLabelStyle);
            dictionary.Add(_stackLayoutSpacingStyle);
        }

        static readonly Style _stackLayoutSpacingStyle = new(typeof(StackBase))
        {
            Setters =
            {
                new(){ Property = StackBase.SpacingProperty, Value = 6 }
            },
            ApplyToDerivedTypes = true
        };

        static readonly Style _pageTitleLabelStyle = new(typeof(Label))
        {
            Class = "pageTitle",
            Setters =
            {
                new (){ Property = Label.HorizontalOptionsProperty, Value = LayoutOptions.Center },
                new (){ Property = Label.FontSizeProperty, Value = 30 },
                new (){ Property = Label.TextColorProperty, Value = Colors.Black },
                new (){ Property = Label.FontAttributesProperty, Value = FontAttributes.Bold },
            }
        };
    }

And in order to apply it to your app, add this to App constructor:

public class App : BlazorBindingsApplication<AppShell>
{
    public App(IServiceProvider services) : base(services)
    {
        Styles.ApplyTo(Resources);
    }
}
Dreamescaper commented 1 year ago

As for CSS styles, StyleSheet razor component is made to allow applying CSS styles to separate elements (pages, etc) - that's why it is expected that this element is added as a child to the element you want to apply it to.

If you want to apply it globally, you probably don't need to use it in razor files at all, just add something like that to your App constructor:

using BlazorBindings.Maui;
using Microsoft.Maui.Controls.StyleSheets;

public class App : BlazorBindingsApplication<AppShell>
{
    public App(IServiceProvider services) : base(services)
    {
        Resources.Add(StyleSheet.FromResource("Resources/Styles/styles.css", GetType().Assembly));
    }
}
Dreamescaper commented 1 year ago

But you certainly right that I should add a sample for styling...

CeSun commented 1 year ago

But you certainly right that I should add a sample for styling...

I also agree with the proposal of this issue, every time I try blazorbindings again, I need to check how to introduce the resource of the third-party component。

   class App : BlazorBindingsApplication<AppShell>
    {
        public App(IServiceProvider services) : base(services)
        {
            Resources.Add(new MaterialStyles());
        }
    }

image

Dreamescaper commented 1 year ago

I'm wondering whether there's anything related in MAUI's documentation regarding that. Because this staff is not razor-specific, that's what you would do in regular MAUI if you don't want to use XAML.

Actually, the opposite is probably true as well, I think it is possible to define App with XAML for use with BlazorBindings, and include the resources there. Which kinda defeats the purpose, but anyway...

shugaoye commented 1 year ago

I tested to add styles at App level per your suggestion and it works fine for me. Is there a way to add style at page or component level? Is it possible to support blazor css isolation? If you add a sample, that will be great.

Dreamescaper commented 1 year ago

Style property wasn't added to razor bindings, as there is no good way to define Style with Razor syntax. However, it should probably be added at least to support externally defined Styles.

But you can define your styles globally, and apply them based on StyleClasses: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/styles/xaml#style-classes

Alternatively, you can use CSS styles - you can apply them via that StyleSheet component you've mentioned before (e.g. add it as a child for your ContentPage).

I'll work on that to make styling a bit easier in the next release.

Vinny636 commented 8 months ago

I wanted to add something to this discussion. I'm using .NET 8 with the nightly builds (BlazorBindings.Maui.Templates 2.0.8 and BlazorBindings.Maui 2.0.1) and I couldn't get CSS styling to work. It kept telling me that it couldn't find the stylesheet resource.

I finally figured out that you have to make the build action on the stylesheet "MauiCss", then it worked fine.

Here's the code in my App.cs, as an example:

using BlazorBindings.Maui;
using Microsoft.Maui.Controls.StyleSheets;

namespace BlazorBindingsTest
{
    public class App : BlazorBindingsApplication<MainPage>
    {
        public App(IServiceProvider services) : base(services)
        {
            Resources.Add(StyleSheet.FromResource("Resources/Styles/styles.css", GetType().Assembly));
        }
    }
}

Here is the build action on my stylesheet:

Screenshot from Visual Studio 2022

Dreamescaper commented 8 months ago

Sorry for the delay, I need to have a bit of rest, but I'll try to get to it as soon as I can.