【问题标题】:How to use DI in XAML如何在 XAML 中使用 DI
【发布时间】:2018-08-15 05:16:44
【问题描述】:

我希望我不是在想象,但我想我在 Prism 和 XF 中的某个地方看到了一种在 XAML 中使用依赖注入的行为:

 <ContentPage.Behaviors>
   <helpers:MyPageBehavior>
      <x:Arguments>
             Have a type here maybe?
      </x:Arguments>             
   </helpers:MyPageBehavior>        
  </ContentPage.Behaviors>

我的页面行为:

class MyPageBehavior : Behavior<ContentPage>
{
      public MyPageBehavior(ISomeService someService)
      {
      }
}

【问题讨论】:

    标签: xamarin.forms prism


    【解决方案1】:

    您需要使用ContainerProvider。您可以从下面从Prism Unit Tests 获取的示例中看到如何使用它。您会注意到 Mock Converter 需要通过 DI 注入 IEventAggregator。然后,在 XAML 中,您可以使用 ContainerProvider 并传入转换器的类型参数,将转换器添加到 ResourceDictionary。

    模拟转换器

    using System;
    using System.Globalization;
    using Xamarin.Forms;
    using Prism.Forms.Tests.Mocks.Events;
    using Prism.Events;
    
    namespace Prism.Forms.Tests.Mocks.Converters
    {
        public class MockValueConverter : IValueConverter
        {
            private IEventAggregator _eventAggreator { get; }
    
            public MockValueConverter(IEventAggregator eventAggreator)
            {
                _eventAggreator = eventAggreator;
            }
    
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                _eventAggreator.GetEvent<TestActionEvent>().Publish("Convert");
                return value;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                _eventAggreator.GetEvent<TestActionEvent>().Publish("ConvertBack");
                return value;
            }
        }
    }
    

    模拟视图

    <?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:prism="clr-namespace:Prism.Ioc;assembly=Prism.Forms"
        xmlns:converters="using:Prism.Forms.Tests.Mocks.Converters"
        Title="{Binding Title}"
        x:Class="Prism.DI.Forms.Tests.Mocks.Views.XamlViewMock">
        <ContentPage.Resources>
            <ResourceDictionary>
                <prism:ContainerProvider x:TypeArguments="converters:MockValueConverter" x:Key="mockValueConverter" />
            </ResourceDictionary>
        </ContentPage.Resources>
        <Entry x:Name="testEntry"
            Text="{Binding Test,Converter={StaticResource mockValueConverter}}" />
    </ContentPage>
    

    【讨论】:

    • 太棒了!我没有产生幻觉:) 谢谢丹尼尔!你和@brian-lagunas,你们摇滚!
    【解决方案2】:

    假设我们有实现ISomeService 的类SomeService,如下所示:

    namespace YOURAPPNAME.Services
    {
         public class SomeService : ISomeService
         {
              public SomeService()
              {
                  Debug.WriteLine("Some Service Constructor Called");
              }
         }
    }
    

    然后在您的 Xaml 页面中

    <ContentPage ......
             xmlns:services="clr-namespace:YOURAPPNAME.Services;assembly=YOURAPPNAME"
             .....>
    
    <ContentPage.Behaviors>
       <helpers:MyPageBehavior>
          <x:Arguments>
             <services:SomeService />
          </x:Arguments>             
       </helpers:MyPageBehavior>        
    </ContentPage.Behaviors>
    

    【讨论】:

    • 谢谢。这行得通,但问题是它不使用依赖注入,它只是实例化作为参数给出的类型。例如,如果SomeService 被注册为单例,你会看到它的 c-tor 被调用了两次,如果导航到这个页面,返回然后再次导航到它
    • 我首先想到的是使用ServiceLocator。你可以看看这个答案,例如:How to resolve a dependency IValueConverter。就像 Dan S. 在他的回答中建议的那样。但请记住,ServiceLocator 被视为反模式。因此,请花点时间做出这样的决定。
    • 谢谢!我认为在某些情况下使用服务定位器非常有意义,这就是其中之一。
    猜你喜欢
    • 2013-06-15
    • 2023-03-08
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多