İçindeki bağımlılık çözümlemesi Xamarin.Forms
Bu makalede Xamarin.Forms , bir uygulamanın bağımlılık ekleme kapsayıcısının özel oluşturuculara, etkilere ve DependencyService uygulamalarının oluşturulması ve ömrü üzerinde denetimi olması için ' a bir bağımlılık çözümü yönteminin nasıl ekleneceği açıklanmaktadır. Bu makaledeki kod örnekleri, kapsayıcılar örneği kullanılarak bağımlılık çözünürlüğünden alınmıştır.
Xamarin.FormsModel-View-ViewModel (MVVM) modelini kullanan bir uygulama bağlamında, bir bağımlılık ekleme kapsayıcısı, görüntüleme modellerini kaydetmek ve çözümlemek ve Hizmetleri kaydetmek ve bunları görünüm modellerine ekleme için kullanılabilir. Görüntüleme modeli oluşturma sırasında kapsayıcı, gereken tüm bağımlılıkları geçersiz kılar. Bu bağımlılıklar oluşturulmadıysa kapsayıcı önce bağımlılıkları oluşturur ve çözümler. Bağımlılık ekleme hakkında daha fazla bilgi için, ekleme bağımlılıklarının görünüm modellerine örnekleri de dahil olmak üzere bkz. bağımlılık ekleme.
Platform projelerindeki türlerin oluşturulması ve yaşam süresi üzerinde denetim, genellikle tarafından gerçekleştirilir ve Xamarin.Forms Bu, Activator.CreateInstance özel Oluşturucu, efekt ve uygulama örnekleri oluşturmak için yöntemini kullanır DependencyService . Ne yazık ki bu, geliştirici denetimini bu türlerin oluşturulması ve ömrü boyunca kısıtlar ve bunlara bağımlılıklar ekleme imkanına sahiptir. Bu davranış Xamarin.Forms , türlerin nasıl oluşturulacağını (uygulamanın bağımlılık ekleme kapsayıcısı ya da tarafından) denetler Xamarin.Forms . Ancak, içine bağımlılık çözümleme yöntemi ekleme gereksinimi olmadığını unutmayın Xamarin.Forms . Xamarin.Forms bağımlılık çözümleme yöntemi eklenmiş değilse platform projelerindeki türlerin yaşam süresini oluşturmaya ve yönetmeye devam edecektir.
Not
Bu makale Xamarin.Forms , bir bağımlılık ekleme kapsayıcısı kullanarak kayıtlı türleri çözümleyen bir bağımlılık çözümleme yöntemi olan ekleme 'e odaklanırken, kayıtlı türleri çözümlemek için Factory yöntemlerini kullanan bir bağımlılık çözümleme yöntemi eklemek de mümkündür. Daha fazla bilgi için, bkz. Fabrika yöntemleri örneği kullanılarak bağımlılık çözümlemesi .
Ekleme a bağımlılık çözümleme yöntemi
DependencyResolverSınıfı, yöntemini kullanarak bir bağımlılık çözümleme yöntemi ekleme özelliği sağlar Xamarin.FormsResolveUsing . Ardından, Xamarin.Forms belirli bir türün örneğine ihtiyaç duyduğunda, bağımlılık çözümleme yöntemine örneği sağlama fırsatı verilir. Bağımlılık çözümleme yöntemi null istenen bir tür için dönerse, Xamarin.Forms yöntemi kullanılarak tür örneğinin kendisini oluşturma denenmeye geri döner Activator.CreateInstance .
Aşağıdaki örnek, yöntemi ile bağımlılık çözümleme yönteminin nasıl ayarlanacağını gösterir 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 kayıtlı olan herhangi bir türü çözümlemek için Autofac bağımlılık ekleme kapsayıcısını kullanan bir lambda ifadesine ayarlanır. Aksi takdirde, null döndürülür, bu da Xamarin.Forms tür çözümlenmeye neden olur.
Not
Bir bağımlılık ekleme kapsayıcısı tarafından kullanılan API, kapsayıcıya özgüdür. Bu makaledeki kod örnekleri, ve türlerini sağlayan bir bağımlılık ekleme kapsayıcısı olarak Autofac kullanır IContainerContainerBuilder . Alternatif bağımlılık ekleme kapsayıcıları eşit olarak kullanılabilir, ancak burada sunulduğundan farklı API 'Ler kullanır.
Uygulamanın başlatılması sırasında bağımlılık çözümleme yöntemini ayarlama gereksinimi olmadığını unutmayın. Bu, herhangi bir zamanda ayarlanabilir. Tek kısıtlama, Xamarin.Forms uygulamanın bağımlılık yerleştirme kapsayıcısında depolanan türleri tüketme zamanına göre bağımlılık çözümleme yöntemi hakkında bilgi sahibi olmalıdır. Bu nedenle, bağımlılık ekleme kapsayıcısında başlangıçta uygulamanın gerektirdiği hizmetler varsa, bağımlılık çözümleme yönteminin uygulamanın yaşam döngüsünün başlarında ayarlanması gerekir. Benzer şekilde, bağımlılık ekleme kapsayıcısı belirli bir nesnenin oluşturulmasını ve ömrünü yönettiğinde Effect , Xamarin.Forms bunu kullanan bir görünüm oluşturmayı denemeden önce bağımlılık çözümleme yöntemi hakkında bilgi sahibi olmalıdır Effect .
Uyarı
Bir bağımlılık ekleme kapsayıcısına sahip türleri kaydetme ve çözümleme, kapsayıcının her tür oluşturmaya yönelik yansıma kullanımı nedeniyle bir performans maliyetine sahiptir, özellikle de bağımlılıklar uygulamadaki her sayfa gezintisi için yeniden oluşturuluyor. Çok sayıda veya derin bağımlılık varsa, oluşturma maliyeti önemli ölçüde artabilir.
Türleri kaydetme
Bağımlılık çözümleme yöntemiyle çözebilmek için önce türler bağımlılık ekleme kapsayıcısına kaydedilmelidir. Aşağıdaki kod örneği, Autofac kapsayıcısı için örnek uygulamanın sınıfında sunduğu kayıt yöntemlerini gösterir App :
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 bir kapsayıcıdan türleri çözümlemek için bir bağımlılık çözümleme yöntemi kullandığında, genellikle platform projelerinden tür kayıtları gerçekleştirilir. Bu, platform projelerinin özel oluşturuculara, etkilere ve uygulamalarına yönelik türleri kaydettirmesine olanak sağlar DependencyService .
Bir platform projesinden aşağıdaki tür kaydı IContainer yaparak, nesne oluşturulmalıdır, bu, yöntemi çağırarak yapılır BuildContainer . Bu yöntem BuildContainerBuilder , örnek üzerinde Autofac ' i çağırır ve bu, yapılmış kayıtları içeren yeni bir bağımlılık ekleme kapsayıcısı oluşturur.
Aşağıdaki bölümlerde, Logger arabirimini uygulayan bir sınıf ILogger sınıf oluşturuculara eklenir. LoggerSınıfı yöntemi kullanılarak basit günlük işlevselliği uygular Debug.WriteLine ve hizmetlerin özel oluşturuculara, etkilere ve uygulamalarına nasıl ekleneceğini göstermek için kullanılır DependencyService .
Özel oluşturuculara kaydetme
Örnek uygulama, XAML kaynağı aşağıdaki örnekte gösterilen Web videolarını yürüten 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>
VideoPlayerGörünüm, VideoPlayerRenderer videoyu yürütmeye yönelik işlevselliği sağlayan bir 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, VideoPlayerRenderer sınıflar bir bağımsız değişken gerektiren aşağıdaki oluşturucuya sahiptir ILogger :
public VideoPlayerRenderer(ILogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
Tüm platformlarda bağımlılık ekleme kapsayıcısına sahip tür kaydı, RegisterTypes uygulamayı yöntemi ile yükleyen platformundan önce çağrılan yöntemi tarafından gerçekleştirilir LoadApplication(new App()) . Aşağıdaki örnekte RegisterTypes iOS platformunda yöntemi gösterilmektedir:
void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterType<FormsVideoLibrary.iOS.VideoPlayerRenderer>();
App.BuildContainer();
}
Bu örnekte Logger somut tür, arabirim türüne karşı bir eşleme yoluyla kaydedilir ve VideoPlayerRenderer tür arabirim eşlemesi olmadan doğrudan kaydedilir. Kullanıcı, görünümü içeren sayfaya gittiğinde VideoPlayer , bağımlılığı çözümleme kapsayıcısından türü çözümlemek için bağımlılık çözümleme yöntemi çağrılır VideoPlayerRenderer . Bu, türü de çözülecek ve Logger oluşturucuya ekleyecektir VideoPlayerRenderer .
VideoPlayerRendererAndroid platformunda Oluşturucu, bağımsız değişkene ek olarak bir bağımsız değişken gerektirdiğinden biraz daha karmaşıktır ContextILogger :
public VideoPlayerRenderer(Context context, ILogger logger) : base(context)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
Aşağıdaki örnekte, RegisterTypes Android platformunda yöntemi gösterilmektedir:
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 VideoPlayerRenderer bağımlılık ekleme kapsayıcısına kaydeder. Kayıt yöntemi, MainActivity örneği Context bağımsız değişken olarak eklenir ve Logger türün bağımsız değişken olarak eklenmesi gerekir ILogger .
Etkileri kaydetme
Örnek uygulama, örnekleri sayfanın etrafında sürüklemek için dokunma izleme efekti kullanan bir sayfa içerir BoxView . , EffectBoxView Aşağıdaki kod kullanılarak öğesine eklenir:
var boxView = new BoxView { ... };
var touchEffect = new TouchEffect();
boxView.Effects.Add(touchEffect);
TouchEffectSınıfı, RoutingEffect her platformda TouchEffect bir olan sınıfı tarafından uygulanan bir PlatformEffect . Platform TouchEffect sınıfı, sayfanın etrafında sürükleme işlevlerini sağlar BoxView . Bu efekt sınıfları hakkında daha fazla bilgi için bkz. etkileri olayları çağırma.
Tüm platformlarda, TouchEffect sınıfı bir bağımsız değişken gerektiren aşağıdaki oluşturucuya sahiptir ILogger :
public TouchEffect(ILogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
Tüm platformlarda bağımlılık ekleme kapsayıcısına sahip tür kaydı, RegisterTypes uygulamayı yöntemi ile yükleyen platformundan önce çağrılan yöntemi tarafından gerçekleştirilir LoadApplication(new App()) . Aşağıdaki örnekte, RegisterTypes Android platformunda yöntemi gösterilmektedir:
void RegisterTypes()
{
App.RegisterType<ILogger, Logger>();
App.RegisterType<TouchTracking.Droid.TouchEffect>();
App.BuildContainer();
}
Bu örnekte Logger somut tür, arabirim türüne karşı bir eşleme yoluyla kaydedilir ve TouchEffect tür arabirim eşlemesi olmadan doğrudan kaydedilir. Kullanıcı ekli olan bir örneği içeren sayfaya gittiğinde BoxViewTouchEffect , bağımlılık çözümleme yöntemi TouchEffect bağımlılık ekleme kapsayıcısından Platform türünü çözümlemek için çağrılır; bu da, Logger türü çözümleyip TouchEffect oluşturucuya ekler.
DependencyService uygulamalarını kaydetme
Örnek uygulama, DependencyService kullanıcının cihazın resim kitaplığından bir fotoğraf seçmesini sağlamak için her platformda uygulamalar kullanan bir sayfa içerir. IPhotoPickerArabirim, uygulamalar tarafından uygulanan işlevselliği tanımlar DependencyService ve aşağıdaki örnekte gösterilmiştir:
public interface IPhotoPicker
{
Task<Stream> GetImageStreamAsync();
}
Her platform projesinde, PhotoPicker sınıfı IPhotoPicker Platform API 'lerini kullanarak arabirimi uygular. Bu bağımlılık Hizmetleri hakkında daha fazla bilgi için bkz. resim kitaplığından fotoğraf seçme.
İOS ve UWP 'de sınıflar, PhotoPicker bir bağımsız değişken gerektiren aşağıdaki oluşturucuya sahiptir ILogger :
public PhotoPicker(ILogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
Tüm platformlarda bağımlılık ekleme kapsayıcısına sahip tür kaydı, RegisterTypes uygulamayı yöntemi ile yükleyen platformundan önce çağrılan yöntemi tarafından gerçekleştirilir LoadApplication(new App()) . Aşağıdaki örnek, RegisterTypes UWP üzerinde yöntemi göstermektedir:
void RegisterTypes()
{
DIContainerDemo.App.RegisterType<ILogger, Logger>();
DIContainerDemo.App.RegisterType<IPhotoPicker, Services.UWP.PhotoPicker>();
DIContainerDemo.App.BuildContainer();
}
Bu örnekte Logger somut tür, arabirim türüne karşı bir eşleme yoluyla kaydedilir ve PhotoPicker tür Ayrıca bir arabirim eşlemesi aracılığıyla kaydedilir.
PhotoPickerAndroid platformunda Oluşturucu, bağımsız değişkene ek olarak bir bağımsız değişken gerektirdiğinden biraz daha karmaşıktır ContextILogger :
public PhotoPicker(Context context, ILogger logger)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
Aşağıdaki örnekte, RegisterTypes Android platformunda yöntemi gösterilmektedir:
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 PhotoPicker bağımlılık ekleme kapsayıcısına kaydeder. Kayıt yöntemi, MainActivity örneği Context bağımsız değişken olarak eklenir ve Logger türün bağımsız değişken olarak eklenmesi gerekir ILogger .
Kullanıcı fotoğraf çekme sayfasına gittiğinde ve bir fotoğraf seçmeye seçerse, 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, PhotoPicker türü de çözülecek ve oluşturucuya eklenecek olan bağımlılık ekleme kapsayıcısından türü çözümlemek için çağrılır LoggerPhotoPicker .
Not
Resolve<T>Yöntemi aracılığıyla uygulamanın bağımlılık ekleme kapsayıcısından bir tür çözümlenirken kullanılması gerekir DependencyService .
Örneği indirin