Caliburn.Micro icon indicating copy to clipboard operation
Caliburn.Micro copied to clipboard

Error with global styles (Xamarin.Forms)

Open Wilsmor opened this issue 4 years ago • 10 comments

Hi, I'm new with Caliburn with Xamarin.forms, i'm sorry if the issue is inappropriate.

When I try to set global styles in the App.XAML file, if I use the style in HomeView page or another view, I receive the following error: System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.'

Where? in Application.cs (Droid): protected override object GetInstance(Type service, string key) { return container.GetInstance(service, key); }

Thank you.

Wilsmor avatar Feb 15 '20 13:02 Wilsmor

If i try it with CSS styleSheet, i have the same error.

Wilsmor avatar Feb 15 '20 13:02 Wilsmor

Can we see some code how you placed the styles linked into the app.xaml or if you show a GitHub repository we be better.

mvermef avatar Feb 15 '20 16:02 mvermef

Here is my example code.

First way (using CSS):

My ContentPage:


<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="GIPMobile.Views.HomeView">
    <ContentPage.Resources>
        <StyleSheet Source="../Estilos/gipstyles.css" />
        
    </ContentPage.Resources>

    <ContentPage.Content>
        <ScrollView>
            <StackLayout Orientation="Vertical" VerticalOptions="Start"  Margin="5,20,5,5" Visual="Material" >
                <Label Text="Estamos probando una APP con Caliburn.Micro"
                   VerticalOptions="CenterAndExpand" 
                   HorizontalOptions="CenterAndExpand"
                   FontSize="25"
                   HorizontalTextAlignment="Center"/>
                
                <Grid Visual="Material">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <Entry Text="{Binding Nombre}" 
                           Placeholder="Nombre en un grid" Margin="10" 
                    MaxLength="15" 
                    Grid.Column="0"
                     />
                    <Label Grid.Column="1" VerticalOptions="Center">Aqui está la columna 2</Label>
                </Grid>
                <Entry Text="{Binding Nombre}" 
                    Placeholder="Nombre" Margin="10" 
                    MaxLength="15" 
                    x:Name="GlobalCajas"/>

                <Entry Text="{Binding Apellidos}" 
                       Placeholder="Apellidos" Margin="10"
                       />
                <Entry Text="{Binding Direccion}" 
                       Placeholder="Dirección" Margin="10" 
                      />
                <StackLayout BackgroundColor="Beige">
                    <Label Text="{Binding Nombre}" Margin="10,30,10,10" TextColor="Black"/>
                    <Label Text="{Binding Apellidos}" Margin="10,10,10,10" TextColor="Black"/>
                    <Label Text="{Binding Direccion}" Margin="10,10,10,10" TextColor="Black"/>
                </StackLayout>
                <Label Text="Uso de stringformat..." Margin="10,10,10,10"/>
                <Label Text="{Binding Nombre,StringFormat='Nombre {0}'}"/>
            </StackLayout>
        </ScrollView>

    </ContentPage.Content>
</ContentPage>

Here is my BootApp file:

using Caliburn.Micro;
using Caliburn.Micro.Xamarin.Forms;
using GIPMobile.ViewModels;
using GIPMobile.Views;
using Xamarin.Forms;
using INavigationService=Caliburn.Micro.Xamarin.Forms.INavigationService;

namespace GIPMobile
{
    public class BootApp: FormsApplication
    {
        private readonly SimpleContainer container;

        public BootApp(SimpleContainer container)
        {
            Initialize();
            
            container.PerRequest<HomeViewModel>();
            
            DisplayRootView<HomeView>(); //view first
            //DisplayRootViewFor <HomeViewModel>(); // ViewModel first
        }

        protected override void PrepareViewFirst(NavigationPage navigationPage)
        {
            container.Instance<INavigationService>(new NavigationPageAdapter(navigationPage));
        }
      
    }
}

Here Application.cs (droid app):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Caliburn.Micro;
using GIPMobile.ViewModels;

namespace GIPMobile.Droid
{
    [Application]
    public class Application : CaliburnApplication
    {
        private SimpleContainer container;

        public Application(IntPtr javaReference, JniHandleOwnership transfer)
            : base(javaReference, transfer)
        {

        }

        public override void OnCreate()
        {
            base.OnCreate();

            Initialize();
        }

        protected override void Configure()
        {
            container = new SimpleContainer();
            container.Instance(container);
            container.Singleton<BootApp>();
        }

        protected override IEnumerable<Assembly> SelectAssemblies()
        {
            return new[]
            {
                GetType().Assembly,
                typeof (HomeViewModel).Assembly
            };
        }

        protected override void BuildUp(object instance)
        {
            container.BuildUp(instance);
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return container.GetAllInstances(service);
        }

        protected override object GetInstance(Type service, string key)
        {
            return container.GetInstance(service, key);
        }
    }
}

Here MainActivity.cs (droid app):

using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Caliburn.Micro;

namespace GIPMobile.Droid
{
    [Activity(Label = "GIPMobile", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            Xamarin.Forms.Forms.Init(this, bundle);
            LoadApplication(IoC.Get<BootApp>());
        }
    }
}

And the last one, stylesheet:

^ContentPage 
{
    background-color:silver;
}
^Entry
{
    background-color:aqua;
    font-size:large;  
}
#GlobalCajas
{
    background-color:orange;
}

Wilsmor avatar Feb 16 '20 10:02 Wilsmor

And second way, using app.xaml (i dont know if it'd be a correct way) writing here the Application resources.

App.xaml

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="GIPMobile.App">
    <Application.Resources>
        <ResourceDictionary>
            <Style TargetType="ContentPage">
                <Setter Property="BackgroundColor" Value="Silver"></Setter>
            </Style>
            <Style TargetType="Entry">
                <Setter Property="BackgroundColor" Value="Aqua"></Setter>
            </Style>
            <Style x:Key="GlobalCajas" TargetType="Entry">
                <Setter Property="BackgroundColor" Value="Orange"></Setter>
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Here homeview.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="GIPMobile.Views.HomeView">
    
    <ContentPage.Content>
        <ScrollView>
            <StackLayout Orientation="Vertical" VerticalOptions="Start"  Margin="5,20,5,5" Visual="Material" >
                <Label Text="Estamos probando una APP con Caliburn.Micro"
                   VerticalOptions="CenterAndExpand" 
                   HorizontalOptions="CenterAndExpand"
                   FontSize="25"
                   HorizontalTextAlignment="Center"/>
                
                <Grid Visual="Material">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <Entry Text="{Binding Nombre, Mode=TwoWay, UpdateSourceEventName=PropertyChanged}" 
                           Placeholder="Nombre en un grid" Margin="10" 
                    MaxLength="15" 
                    Grid.Column="0"
                     />
                    <Label Grid.Column="1" VerticalOptions="Center">Aqui está la columna 2</Label>
                </Grid>
                <Entry Text="{Binding Nombre, Mode=TwoWay, UpdateSourceEventName=PropertyChanged}" 
                    Placeholder="Nombre" Margin="10" 
                    MaxLength="15" 
                    Style="{StaticResource GlobalCajas}"/>

                <Entry Text="{Binding Apellidos, Mode=TwoWay}" 
                       Placeholder="Apellidos" Margin="10"
                       />
                <Entry Text="{Binding Direccion}" 
                       Placeholder="Dirección" Margin="10" 
                      />
                <StackLayout BackgroundColor="Beige">
                    <Label Text="{Binding Nombre}" Margin="10,30,10,10" TextColor="Black"/>
                    <Label Text="{Binding Apellidos}" Margin="10,10,10,10" TextColor="Black"/>
                    <Label Text="{Binding Direccion}" Margin="10,10,10,10" TextColor="Black"/>
                </StackLayout>
                <Label Text="Uso de stringformat..." Margin="10,10,10,10"/>
                <Label Text="{Binding Nombre,StringFormat='Nombre {0}'}"/>
            </StackLayout>
        </ScrollView>

    </ContentPage.Content>
</ContentPage>

And my HomeViewModel:

using Caliburn.Micro;
using System;
using System.Collections.Generic;
using System.Text;

namespace GIPMobile.ViewModels
{
    public class HomeViewModel :Screen
    {
		private string _nombre;
		public string Nombre
		{
			get { return _nombre; }
			set
			{
				_nombre = value;
				NotifyOfPropertyChange(() => Nombre);
			}
		}

		private string _apellidos;
		public string Apellidos
		{
			get { return _apellidos; }
			set
			{
				_apellidos = value;
				NotifyOfPropertyChange(() => Apellidos);
			}
		}

		private string _direccion;
		public string Direccion
		{
			get { return _direccion; }
			set
			{
				_direccion = value;
				NotifyOfPropertyChange(() => Direccion);
			}
		}
	}
}

I havo to say, while i am at design time, i can see the styles changes in designer window.

Thank you. example

Wilsmor avatar Feb 16 '20 10:02 Wilsmor

couple of things... Reference code comments inline with the source snipped from your source.

namespace GIPMobile
{
    public class BootApp: FormsApplication
    {
        private readonly SimpleContainer container;

        public BootApp(SimpleContainer container)
        {
            Initialize();
            this.container = container;   // necessary to initialize it.
            container.PerRequest<HomeViewModel>();
            
            DisplayRootView<HomeView>(); //view first
            //DisplayRootViewFor <HomeViewModel>(); // ViewModel first
        }

        protected override void PrepareViewFirst(NavigationPage navigationPage)
        {
            container.Instance<INavigationService>(new NavigationPageAdapter(navigationPage));
        }
      
    }
}
 protected override void Configure()
        {
            container = new SimpleContainer();
            ///            container.Instance(container); //DON"T DO THIS...
            container.Singleton<BootApp>();
        }

This was the ultimate reason for it not to work in the droid flavor. the container already knows about itself it doesn't need to be inserted back into the container.


 <Application.Resources>
        <ResourceDictionary.MergeDictionaries>
            <ResourceDictionary>
            <Style TargetType="ContentPage">
                <Setter Property="BackgroundColor" Value="Silver"></Setter>
            </Style>
            <Style TargetType="Entry">
                <Setter Property="BackgroundColor" Value="Aqua"></Setter>
            </Style>
            <Style x:Key="GlobalCajas" TargetType="Entry">
                <Setter Property="BackgroundColor" Value="Orange"></Setter>
            </Style>
        </ResourceDictionary>
      <ResourceDictionary.MergeDictionaries>
    </Application.Resources>

To be honest it had nothing to do with the Styles in my opinion. IT had everything to do with the container not being this.container = container in one location and then you trying to insert the container into its self.

mvermef avatar Feb 16 '20 17:02 mvermef

Hi, thank you. I agree, writing this.conainer = conainter it works. But it is working with CSS stylesheet, but not with App.xaml and application.resources. It´s like caliburn didnt found app.xaml. How can i register it in caliburn´s container?

Wilsmor avatar Feb 18 '20 08:02 Wilsmor

To clarify, when i try work with xaml styles, i don´t use CSS. I don´t mix them.

Wilsmor avatar Feb 18 '20 08:02 Wilsmor

Does this work in a project without Caliburn.Micro at all?

nigel-sampson avatar Feb 18 '20 08:02 nigel-sampson

Yes, it does.

Wilsmor avatar Feb 18 '20 08:02 Wilsmor

I'm having the exact same issue with 'V4.0.113' The resources from my app.xaml aren't used/found. image All other things are almost identicall to Wilsmor.

Update: After changing back the 'Application' back to the 'FormsApplication' and not use 'BootApp.cs' seperatly (and of course load the app class instead of bootapp class). This worked again! Don't forget to set: 'InitializeComponent()' in the Constructor of the app, because otherwise it won't work (without any errors) image

Zarkos69 avatar Feb 27 '20 14:02 Zarkos69