Aracılığıyla paylaş


içindeki bağımlılık çözümlemesi Xamarin.Forms

Bu makalede, bir uygulamanın bağımlılık ekleme kapsayıcısının özel işleyicilerin, efektlerin ve DependencyService uygulamalarının oluşturulması ve ömrü üzerinde denetime sahip olması için içine bir bağımlılık çözümleme yönteminin Xamarin.Forms nasıl eklendiğini açıklanmaktadır.

Model-View-ViewModel (MVVM) desenini kullanan bir Xamarin.Forms uygulama bağlamında, görünüm modellerini kaydetmek ve çözümlemek, hizmetleri kaydetmek ve görünüm modellerine eklemek için bir bağımlılık ekleme kapsayıcısı kullanılabilir. Görünüm modeli oluşturma sırasında kapsayıcı, gerekli olan tüm bağımlılıkları ekler. Bu bağımlılıklar oluşturulmadıysa kapsayıcı önce bağımlılıkları oluşturur ve çözer. Görünüm modellerine bağımlılık ekleme örnekleri de dahil olmak üzere bağımlılık ekleme hakkında daha fazla bilgi için bkz . Bağımlılık Ekleme.

Platform projelerindeki türlerin oluşturulması ve yaşam süresi üzerinde denetim geleneksel olarak tarafından Xamarin.Formsgerçekleştirilir ve bu yöntem, özel işleyicilerin, efektlerin ve DependencyService uygulamaların örneklerini oluşturmak için yöntemini kullanırActivator.CreateInstance. Ne yazık ki bu, bu türlerin oluşturulması ve kullanım ömrü üzerinde geliştirici denetimini ve bunlara bağımlılık ekleme özelliğini sınırlar. Bu davranış, uygulamanın bağımlılık ekleme kapsayıcısı veya Xamarin.Formstarafından türlerin nasıl oluşturulacağını denetleyecek bir bağımlılık çözümleme yöntemi Xamarin.Forms eklenerek değiştirilebilir. Ancak, içine bir bağımlılık çözümleme yöntemi Xamarin.Formsekleme gereksinimi olmadığını unutmayın. Xamarin.Forms bir bağımlılık çözümleme yöntemi eklenmemişse platform projelerinde türlerin yaşam ömrünü oluşturmaya ve yönetmeye devam eder.

Not

Bu makale, bağımlılık ekleme kapsayıcısı kullanarak kayıtlı türleri çözümleyen bir bağımlılık çözümleme yöntemi eklemeye Xamarin.Forms odaklansa da, kayıtlı türleri çözümlemek için fabrika yöntemlerini kullanan bir bağımlılık çözümleme yöntemi eklemek de mümkündür.

Bağımlılık çözümleme yöntemi ekleme

sınıfı, DependencyResolver yöntemini kullanarak ResolveUsing içine Xamarin.Formsbir bağımlılık çözümleme yöntemi ekleme olanağı sağlar. Ardından, belirli bir türün örneğine ihtiyaç duyduğunda Xamarin.Forms , bağımlılık çözümleme yöntemine örneği sağlama fırsatı verilir. Bağımlılık çözümleme yöntemi istenen bir tür için döndürürse null , Xamarin.Forms yöntemini kullanarak Activator.CreateInstance tür örneğini oluşturmaya çalışmaya geri döner.

Aşağıdaki örnekte, yöntemiyle bağımlılık çözümleme yönteminin nasıl ayarlanacağı gösterilmektedir ResolveUsing :

using Autofac;
using Xamarin.Forms.Internals;
...

public partial class App : Application
{
    // IContainer and ContainerBuilder are provided by Autofac
    static IContainer container;
    static readonly ContainerBuilder builder = new ContainerBuilder();

    public App()
    {
        ...
        DependencyResolver.ResolveUsing(type => container.IsRegistered(type) ? container.Resolve(type) : null);
        ...
    }
    ...
}

Bu örnekte bağımlılık çözümleme yöntemi, kapsayıcıya kaydedilmiş tüm türleri çözümlemek için Autofac bağımlılık ekleme kapsayıcısını kullanan bir lambda ifadesi olarak ayarlanmıştır. Aksi takdirde döndürülür null ve bu da türün çözümlenmesine neden Xamarin.Forms olur.

Not

Bağımlılık ekleme kapsayıcısı tarafından kullanılan API kapsayıcıya özgüdür. Bu makaledeki kod örnekleri, ve ContainerBuilder türlerini sağlayan bağımlılık ekleme kapsayıcısı olarak Autofac'ı IContainer kullanır. Alternatif bağımlılık ekleme kapsayıcıları eşit olarak kullanılabilir, ancak burada sunulandan farklı API'ler kullanabilir.

Uygulama başlatma sırasında bağımlılık çözümleme yöntemini ayarlama gereksinimi olmadığını unutmayın. İstediğiniz zaman ayarlanabilir. Tek kısıtlama, Xamarin.Forms uygulamanın bağımlılık ekleme kapsayıcısında depolanan türleri tüketmeye çalıştığı zamana kadar bağımlılık çözümleme yöntemi hakkında bilgi edinmesi gerekir. Bu nedenle, bağımlılık ekleme kapsayıcısında uygulamanın başlatma sırasında gerektireceği hizmetler varsa, bağımlılık çözümleme yönteminin uygulamanın yaşam döngüsünün erken aşamalarında ayarlanması gerekir. Benzer şekilde, bağımlılık ekleme kapsayıcısı belirli Effectbir öğesinin oluşturulmasını ve ömrünü yönetiyorsa, Xamarin.Forms bunu kullanan Effectbir görünüm oluşturmaya çalışmadan önce bağımlılık çözümleme yöntemi hakkında bilgi sahibi olması gerekir.

Uyarı

Bağımlılık ekleme kapsayıcısıyla türleri kaydetme ve çözme, özellikle uygulamadaki her sayfa gezintisi için bağımlılıklar yeniden yapılandırılıyorsa, kapsayıcının her türü oluşturmak için yansıma kullanması nedeniyle performans maliyetine sahiptir. Çok veya derin bağımlılıklar varsa oluşturma maliyeti önemli ölçüde artabilir.

Türler kaydediliyor

Türlerin bağımlılık çözümleme yöntemiyle çözümlenebilmesi için önce bağımlılık ekleme kapsayıcısıyla kaydedilmesi gerekir. Aşağıdaki kod örneği, örnek uygulamanın Autofac kapsayıcısı için sınıfında kullanıma sunma App kayıt yöntemlerini gösterir:

using Autofac;
using Autofac.Core;
...

public partial class App : Application
{
    static IContainer container;
    static readonly ContainerBuilder builder = new ContainerBuilder();
    ...

    public static void RegisterType<T>() where T : class
    {
        builder.RegisterType<T>();
    }

    public static void RegisterType<TInterface, T>() where TInterface : class where T : class, TInterface
    {
        builder.RegisterType<T>().As<TInterface>();
    }

    public static void RegisterTypeWithParameters<T>(Type param1Type, object param1Value, Type param2Type, string param2Name) where T : class
    {
        builder.RegisterType<T>()
               .WithParameters(new List<Parameter>()
        {
            new TypedParameter(param1Type, param1Value),
            new ResolvedParameter(
                (pi, ctx) => pi.ParameterType == param2Type && pi.Name == param2Name,
                (pi, ctx) => ctx.Resolve(param2Type))
        });
    }

    public static void RegisterTypeWithParameters<TInterface, T>(Type param1Type, object param1Value, Type param2Type, string param2Name) where TInterface : class where T : class, TInterface
    {
        builder.RegisterType<T>()
               .WithParameters(new List<Parameter>()
        {
            new TypedParameter(param1Type, param1Value),
            new ResolvedParameter(
                (pi, ctx) => pi.ParameterType == param2Type && pi.Name == param2Name,
                (pi, ctx) => ctx.Resolve(param2Type))
        }).As<TInterface>();
    }

    public static void BuildContainer()
    {
        container = builder.Build();
    }
    ...
}

Bir uygulama kapsayıcıdan türleri çözümlemek için bağımlılık çözümleme yöntemi kullandığında, tür kayıtları genellikle platform projelerinden gerçekleştirilir. Bu, platform projelerinin özel işleyiciler, efektler ve DependencyService uygulamalar için türleri kaydetmesini sağlar.

Bir platform projesinden tür kaydından IContainer sonra nesnesi oluşturulmalıdır ve bu yöntem çağrılarak BuildContainer gerçekleştirilir. Bu yöntem, yapılan kayıtları içeren yeni bir bağımlılık ekleme kapsayıcısı oluşturan örnekte Autofac'ın Build yöntemini ContainerBuilder çağırır.

Izleyen bölümlerde, arabirimini uygulayan ILogger bir Logger sınıf sınıf oluşturucularına eklenir. sınıfı Logger , yöntemini kullanarak Debug.WriteLine basit günlük işlevi uygular ve hizmetlerin özel işleyicilere, efektlere ve DependencyService uygulamalara nasıl eklendiğini göstermek için kullanılır.

Özel işleyicileri kaydetme

Örnek uygulama, aşağıdaki örnekte XAML kaynağı gösterilen web videoları oynatan bir sayfa içerir:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:video="clr-namespace:FormsVideoLibrary"
             ...>
    <video:VideoPlayer Source="https://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4" />
</ContentPage>

Görünüm VideoPlayer , videoyu oynatma işlevselliği sağlayan bir VideoPlayerRenderer sınıf tarafından her platformda uygulanır. Bu özel işleyici sınıfları hakkında daha fazla bilgi için bkz . Video oynatıcı uygulama.

iOS ve Evrensel Windows Platformu (UWP) üzerinde sınıflarVideoPlayerRenderer, bağımsız ILogger değişken gerektiren aşağıdaki oluşturucuya sahiptir:

public VideoPlayerRenderer(ILogger logger)
{
    _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Tüm platformlarda, bağımlılık ekleme kapsayıcısı ile tür kaydı, platform uygulamayı yöntemiyle yüklemeden önce çağrılan yöntemi tarafından RegisterTypesLoadApplication(new App()) gerçekleştirilir. Aşağıdaki örnekte iOS platformundaki yöntemi gösterilmektedir RegisterTypes :

void RegisterTypes()
{
    App.RegisterType<ILogger, Logger>();
    App.RegisterType<FormsVideoLibrary.iOS.VideoPlayerRenderer>();
    App.BuildContainer();
}

Bu örnekte somut tür, Logger arabirim türüne göre eşleme yoluyla kaydedilir ve VideoPlayerRenderer tür doğrudan arabirim eşlemesi olmadan kaydedilir. Kullanıcı görünümü içeren VideoPlayer sayfaya gittiği zaman bağımlılık çözümleme yöntemi, bağımlılık ekleme kapsayıcısından türü çözümlemek VideoPlayerRenderer için çağrılır ve bu da türü çözümleyip oluşturucuya VideoPlayerRenderer eklerLogger.

VideoPlayerRenderer Android platformundaki oluşturucu, bağımsız değişkene ek olarak bir Context bağımsız değişken gerektirdiğinden ILogger biraz daha karmaşıktır:

public VideoPlayerRenderer(Context context, ILogger logger) : base(context)
{
    _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Aşağıdaki örnekte Android platformunda yöntemi gösterilmektedir RegisterTypes :

void RegisterTypes()
{
    App.RegisterType<ILogger, Logger>();
    App.RegisterTypeWithParameters<FormsVideoLibrary.Droid.VideoPlayerRenderer>(typeof(Android.Content.Context), this, typeof(ILogger), "logger");
    App.BuildContainer();
}

Bu örnekte, App.RegisterTypeWithParameters yöntemi bağımlılık ekleme kapsayıcısı ile kaydeder VideoPlayerRenderer . Kayıt yöntemi, örneğin bağımsız değişken olarak Context eklenmiş olmasını ve türün Logger bağımsız değişken olarak ILogger eklenmiş olmasını sağlarMainActivity.

Efektleri kaydetme

Örnek uygulama, örnekleri sayfada sürüklemek BoxView için dokunmatik izleme efekti kullanan bir sayfa içerir. Effect aşağıdaki kod kullanılarak öğesine BoxView eklenir:

var boxView = new BoxView { ... };
var touchEffect = new TouchEffect();
boxView.Effects.Add(touchEffect);

TouchEffect sınıfı, olan bir RoutingEffectTouchEffect sınıf tarafından her platformda uygulanan bir PlatformEffectsınıfıdır. Platform TouchEffect sınıfı, sayfayı sürükleme BoxView işlevselliği sağlar. Bu efekt sınıfları hakkında daha fazla bilgi için bkz . Efektlerden olayları çağırma.

Tüm platformlarda sınıfı TouchEffect , bağımsız ILogger değişken gerektiren aşağıdaki oluşturucuya sahiptir:

public TouchEffect(ILogger logger)
{
    _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Tüm platformlarda, bağımlılık ekleme kapsayıcısı ile tür kaydı, platform uygulamayı yöntemiyle yüklemeden önce çağrılan yöntemi tarafından RegisterTypesLoadApplication(new App()) gerçekleştirilir. Aşağıdaki örnekte Android platformunda yöntemi gösterilmektedir RegisterTypes :

void RegisterTypes()
{
    App.RegisterType<ILogger, Logger>();
    App.RegisterType<TouchTracking.Droid.TouchEffect>();
    App.BuildContainer();
}

Bu örnekte somut tür, Logger arabirim türüne göre eşleme yoluyla kaydedilir ve TouchEffect tür doğrudan arabirim eşlemesi olmadan kaydedilir. Kullanıcı, bağlı örneği TouchEffect içeren BoxView sayfaya gittiği zaman bağımlılık çözümleme yöntemi, bağımlılık ekleme kapsayıcısından platform TouchEffect türünü çözümlemek için çağrılır ve bu yöntem türü çözümleyip oluşturucuya TouchEffect eklerLogger.

DependencyService uygulamalarını kaydetme

Örnek uygulama, kullanıcının cihazın resim kitaplığından bir fotoğraf seçmesine izin vermek için her platformdaki uygulamaları kullanan DependencyService bir sayfa içerir. IPhotoPicker Arabirim, uygulamalar tarafından DependencyService uygulanan işlevselliği tanımlar ve aşağıdaki örnekte gösterilmiştir:

public interface IPhotoPicker
{
    Task<Stream> GetImageStreamAsync();
}

Her platform projesinde PhotoPicker sınıfı, platform API'lerini IPhotoPicker kullanarak arabirimini uygular. Bu bağımlılık hizmetleri hakkında daha fazla bilgi için bkz . Resim kitaplığından fotoğraf seçme.

iOS ve UWP'de sınıflar PhotoPicker , bağımsız ILogger değişken gerektiren aşağıdaki oluşturucuya sahiptir:

public PhotoPicker(ILogger logger)
{
    _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Tüm platformlarda, bağımlılık ekleme kapsayıcısı ile tür kaydı, platform uygulamayı yöntemiyle yüklemeden önce çağrılan yöntemi tarafından RegisterTypesLoadApplication(new App()) gerçekleştirilir. Aşağıdaki örnekte UWP'de RegisterTypes yöntemi gösterilmektedir:

void RegisterTypes()
{
    DIContainerDemo.App.RegisterType<ILogger, Logger>();
    DIContainerDemo.App.RegisterType<IPhotoPicker, Services.UWP.PhotoPicker>();
    DIContainerDemo.App.BuildContainer();
}

Bu örnekte somut tür, Logger arabirim türüne göre eşleme yoluyla kaydedilir ve PhotoPicker tür bir arabirim eşlemesi aracılığıyla da kaydedilir.

PhotoPicker Android platformundaki oluşturucu, bağımsız değişkene ek olarak bir Context bağımsız değişken gerektirdiğinden ILogger biraz daha karmaşıktır:

public PhotoPicker(Context context, ILogger logger)
{
    _context = context ?? throw new ArgumentNullException(nameof(context));
    _logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

Aşağıdaki örnekte Android platformunda yöntemi gösterilmektedir RegisterTypes :

void RegisterTypes()
{
    App.RegisterType<ILogger, Logger>();
    App.RegisterTypeWithParameters<IPhotoPicker, Services.Droid.PhotoPicker>(typeof(Android.Content.Context), this, typeof(ILogger), "logger");
    App.BuildContainer();
}

Bu örnekte, App.RegisterTypeWithParameters yöntemi bağımlılık ekleme kapsayıcısı ile kaydeder PhotoPicker . Kayıt yöntemi, örneğin bağımsız değişken olarak Context eklenmiş olmasını ve türün Logger bağımsız değişken olarak ILogger eklenmiş olmasını sağlarMainActivity.

Kullanıcı fotoğraf çekme sayfasına gidip bir fotoğraf seçmeyi seçtiğinde OnSelectPhotoButtonClicked işleyici yürütülür:

async void OnSelectPhotoButtonClicked(object sender, EventArgs e)
{
    ...
    var photoPickerService = DependencyService.Resolve<IPhotoPicker>();
    var stream = await photoPickerService.GetImageStreamAsync();
    if (stream != null)
    {
        image.Source = ImageSource.FromStream(() => stream);
    }
    ...
}

DependencyService.Resolve<T> yöntemi çağrıldığında bağımlılık çözümleme yöntemi, bağımlılık ekleme kapsayıcısından türü çözümlemek PhotoPicker için çağrılır ve bu da türü çözümleyip oluşturucuya PhotoPicker eklerLogger.

Not

yöntemi, Resolve<T> aracılığıyla uygulamanın bağımlılık ekleme kapsayıcısından DependencyServicebir tür çözümlendiğinde kullanılmalıdır.