只有默认构造函数被调用

huangapple go评论71阅读模式
英文:

Only default constructor is called

问题

以下是代码部分的翻译,不包含问题或其他内容:

我正在尝试将服务传递给 MAUI 组件的构造函数:

public partial class MyComponent: ContentView
{
    public MyComponent(MyService service)
    {
        InitializeComponent();

        data = service.getData();
    }
}

但它会引发错误,并要求添加默认构造函数:

public partial class MyComponent: ContentView
{
    public MyComponent() { }

    public MyComponent(MyService service)
    {
        InitializeComponent();

        data = service.getData();
    }
}

我添加了单例以将服务传递给组件:

builder.Services.AddSingleton<MyComponent>();
builder.Services.AddSingleton<MyService>();

我还尝试了这种方法:

builder.Services.AddSingleton(sp => new MyComponent(sp.GetService<MyService>()));

但它们都没有起作用,只调用了默认构造函数。

我在页面中使用组件,像这样:

<ContentPage ...
             xmlns:components="clr-namespace:MyApp.Components">
        <components:MyComponent/>
</ContentPage>

如何将服务传递给组件?

英文:

I'm trying to pass a service to a component constructor in MAUI:

public partial class MyComponent: ContentView
{
    public MyComponent(MyService service)
    {
        InitializeComponent();

        data = service.getData();
    }
}

But it throws error and asks to add a default constructor:

public partial class MyComponent: ContentView
{

    public MyComponent() { }

    public MyComponent(MyService service)
    {
        InitializeComponent();

        data = service.getData();

    }
}

I added singletons to pass the service to the component:

builder.Services.AddSingleton&lt;MyComponent&gt;();
builder.Services.AddSingleton&lt;MyService&gt;();

I also tried this method:

builder.Services.AddSingleton(sp =&gt; new MyComponent(sp.GetService&lt;MyService&gt;()));

None of them worked. Only default constructor called

I use the component in a page like this:

&lt;ContentPage ...
             xmlns:components=&quot;clr-namespace:MyApp.Components&quot;&gt;
        &lt;components:MyComponent/&gt;
&lt;/ContentPage&gt;

How do I pass a service to a component?

答案1

得分: 1

你无法在自定义控件中直接使用依赖注入。

请查看GitHub上的此问题:自定义控件的依赖注入。它仍然是一个正在考虑的增强功能,你可以关注此问题。

应该有一些解决方法。就像上面问题中的tripjump评论所提到的,你可以附加一个可绑定属性,并通过这个属性从MainPage注入viewModel。我为你制作了一个小演示。

对于MyComponent控件:

public partial class MyComponent : ContentView
{
    public static readonly BindableProperty ServiceProperty = BindableProperty.Create(nameof(Service), typeof(MyService), typeof(MyComponent), propertyChanged: OnServiceChanged);

    static void OnServiceChanged(BindableObject bindable, object oldValue, object newValue)
    {
        // 属性更改的实现在这里
        MyService a = newValue as MyService;
    }

    public MyService Service
    {
        get => (MyService)GetValue(MyComponent.ServiceProperty);
        set => SetValue(MyComponent.ServiceProperty, value);
    }

    public MyComponent()
    {
        InitializeComponent();
    }
}

对于消耗MyComponent的MainPage:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             ...
             x:Name="this">

    <components:MyComponent BindingContext="{x:Reference this}" MyService="{Binding BindingContext.service}"/>
</ContentPage>

对于作为MainPage的BindingContext的MainPageViewModel:

public class MainPageViewModel
{
    public MyService service { get; set; }

    public MainPageViewModel(MyService myService)
    {
        service = myService;
    }
}

还需要在MauiProgram中添加service:

builder.Services.AddSingleton<MainPage>();
builder.Services.AddSingleton<MainPageViewModel>();
builder.Services.AddSingleton<MyService>();

希望对你有所帮助。

英文:

You could not directly use dependency injection in a custom control.

See this issue on Github: Dependency Injection for Custom Controls. It's still enhancement under consideration and you could follow this issue.

There should be some workarounds. Just as tripjump comment in above issue, you could attach a bindable property and inject the viewModel from MainPage through this property. I just made a small demo for you.

For MyComponent control:

public partial class MyComponent : ContentView
{

    public static readonly BindableProperty ServiceProperty = BindableProperty.Create(nameof(Service),typeof(MyService), typeof(MyComponent),propertyChanged: OnServiceChanged);

    static void OnServiceChanged(BindableObject bindable, object oldValue, object newValue)
    {
    // Property changed implementation goes here
        MyService a = newValue as MyService;
    }

    public MyService Service
    {
        get =&gt; (MyService)GetValue(MyComponent.ServiceProperty);
        set =&gt; SetValue(MyComponent.ServiceProperty, value);
    }

    public MyComponent()
    {
	    InitializeComponent();
    }
}

For MainPage which consumes MyComponent:

&lt;ContentPage xmlns=&quot;http://schemas.microsoft.com/dotnet/2021/maui&quot;
         ...
         x:Name=&quot;this&quot;&gt;

&lt;components:MyComponent BindingContext=&quot;{x:Reference this}&quot; MyService=&quot;{Binding BindingContext.service}&quot;/&gt;

For MainPageViewModel which is BindingContext of MainPage:

public class MainPageViewModel
{
	public MyService service { get; set; }

	public MainPageViewModel(MyService myService)
	{
		service = myService;
	}
}

And also add service in MauiProgram:

	builder.Services.AddSingleton&lt;MainPage&gt;();
    builder.Services.AddSingleton&lt;MainPageViewModel&gt;();
    builder.Services.AddSingleton&lt;MyService&gt;();

Hope it works for you.

答案2

得分: 1

可以使用依赖注入,就像这里中所示。

创建一个ServiceProvider类:

public static class ServiceProvider
{
    public static TService GetService<TService>()
        => Current.GetService<TService>();

    public static IServiceProvider Current =>
#if WINDOWS10_0_17763_0_OR_GREATER
        MauiWinUIApplication.Current.Services;
#elif ANDROID
        MauiApplication.Current.Services;
#elif IOS || MACCATALYST
        MauiUIApplicationDelegate.Current.Services;
#else
        null;
#endif
}

然后,你可以在任何组件的构造函数中简单地使用它:

_Contexte = ServiceHelper.GetService<Contexte>();

至于为什么无法向XAML组件传递参数,那是因为它们会被转换为C#代码,然后自动处理。如果构造函数有参数,处理转换的机制将不知道应该传递给构造函数的实例(除非Microsoft决定处理依赖注入,这可能会在某个时候发生)。

英文:

You can also use dependency injection like in there.

Create a ServiceProvider class :

public static class ServiceProvider
{
    public static TService GetService&lt;TService&gt;()
        =&gt; Current.GetService&lt;TService&gt;();

    public static IServiceProvider Current
        =&gt;
#if WINDOWS10_0_17763_0_OR_GREATER
			MauiWinUIApplication.Current.Services;
#elif ANDROID
            MauiApplication.Current.Services;
#elif IOS || MACCATALYST
			MauiUIApplicationDelegate.Current.Services;
#else
			null;
#endif
}

Then you can simply use it in any component constructor :

_Contexte = ServiceHelper.GetService&lt;Contexte&gt;();

As for why you can't pass parameter to XAML components it's because they are converted to C# code and then automatically process. If the constructor has argument the mechanism handling the conversion wont know which instance to pass to the constructor (unless microsoft decide to handle DI, which may happend at some point).

huangapple
  • 本文由 发表于 2023年2月14日 07:56:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75442254.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定