0

I hope I'm not imagining but I think I saw somewhere a way in Prism and XF to have a behavior use dependency injection in XAML:

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

MyPageBehavior:

class MyPageBehavior : Behavior<ContentPage>
{
      public MyPageBehavior(ISomeService someService)
      {
      }
}
Don Box
  • 3,166
  • 3
  • 26
  • 55

2 Answers2

2

Assume we have class SomeService that implements ISomeService, like below:

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

then in your Xaml page

<ContentPage ......
         xmlns:services="clr-namespace:YOURAPPNAME.Services;assembly=YOURAPPNAME"
         .....>

<ContentPage.Behaviors>
   <helpers:MyPageBehavior>
      <x:Arguments>
         <services:SomeService />
      </x:Arguments>             
   </helpers:MyPageBehavior>        
</ContentPage.Behaviors>
Khaled Gaber
  • 121
  • 6
  • Thanks. That works but the problem with that is it doesn't use dependency injection, it just instantiates the types given as arguments. For example, if `SomeService` is registered as a singleton, you will see its c-tor called twice, if navigate to this page, go back and then navigate again to it – Don Box Aug 14 '18 at 12:49
  • The first thing that comes to my mind is by using a `ServiceLocator`. You may take a look at this answer for example: [How to resolve a dependency IValueConverter](https://stackoverflow.com/questions/49892472/how-to-resolve-a-dependency-in-ivalueconverter-in-xamarin-forms-using-prism-dryi). just like Dan S. suggested in his answer. but keep in mind, `ServiceLocator` is considered an antipattern. So take your time in making such a decision. – Khaled Gaber Aug 15 '18 at 10:00
  • Thanks! I think using service locator makes perfect sense in some cases, and this is one of them. – Don Box Aug 16 '18 at 06:57
2

You'll want to use the ContainerProvider. You can see from the sample below taken from the Prism Unit Tests how to use this. You'll notice the Mock Converter requires the IEventAggregator be injected via DI. In XAML you are able to then add the converter to the ResourceDictionary by using the ContainerProvider and passing in the Type Argument for the Converter.

MockConverter

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;
        }
    }
}

Mock View

<?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>
Dan Siegel
  • 5,724
  • 2
  • 14
  • 28