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 Effect
bir öğesinin oluşturulmasını ve ömrünü yönetiyorsa, Xamarin.Forms bunu kullanan Effect
bir 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 RegisterTypes
LoadApplication(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 RoutingEffect
TouchEffect
sınıf tarafından her platformda uygulanan bir PlatformEffect
sı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 RegisterTypes
LoadApplication(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 RegisterTypes
LoadApplication(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 DependencyService
bir tür çözümlendiğinde kullanılmalıdır.