Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Az Androidhoz készült .NET-build részeként az Android-erőforrások feldolgozásra kerülnek, és egy generált szerelvényen keresztül felfedik az _Microsoft.Android.Resource.Designer.dll.
Például a tartalommal rendelkező fájlra Reources\layout\Main.axml vonatkozóan:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android">
<Button android:id="@+id/myButton" />
<fragment
android:id="@+id/log_fragment"
android:name="commonsamplelibrary.LogFragment"
/>
<fragment
android:id="@+id/secondary_log_fragment"
android:name="CommonSampleLibrary.LogFragment"
/>
</LinearLayout>
A buildelési idő alatt egy _Microsoft.Android.Resource.Designer.dll szerelvény a következőhöz hasonló tartalommal rendelkezik:
namespace _Microsoft.Android.Resource.Designer;
partial class Resource {
partial class Id {
public static int myButton {get;}
public static int log_fragment {get;}
public static int secondary_log_fragment {get;}
}
partial class Layout {
public static int Main {get;}
}
}
Az erőforrások használata hagyományosan kódban történik, a típus és a ResourceFindViewById<T>() metódus állandóinak használatával:
partial class MainActivity : Activity {
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.Main);
Button button = FindViewById<Button>(Resource.Id.myButton);
button.Click += delegate {
button.Text = $"{count++} clicks!";
};
}
}
A Xamarin.Android 8.4-től kezdve két további módon is használhatja az Android-erőforrásokat a C# használatakor:
Az új funkciók engedélyezéséhez állítsa be a
$(AndroidGenerateLayoutBindings) MSBuild tulajdonság az True msbuild parancssorban:
dotnet build -p:AndroidGenerateLayoutBindings=true MyProject.csproj
vagy a .csproj fájlban:
<PropertyGroup>
<AndroidGenerateLayoutBindings>true</AndroidGenerateLayoutBindings>
</PropertyGroup>
Kötések
A binding egy generált osztály, amely minden Android elrendezésfájlhoz tartozik, és tartalmazza az elrendezésfájlban lévő összes azonosítóhoz tartozó erősen típusos tulajdonságokat. A rendszer kötéstípusokat hoz létre a global::Bindings névtérben az elrendezésfájl fájlnevét tükröző típusnevekkel.
A kötéstípusok minden olyan elrendezésfájlhoz létrejönnek, amelyek bármilyen Android-azonosítót tartalmaznak.
Az Android Layout fájlt Resources\layout\Main.axml alapul véve:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools">
<Button android:id="@+id/myButton" />
<fragment
android:id="@+id/fragmentWithExplicitManagedType"
android:name="commonsamplelibrary.LogFragment"
xamarin:managedType="CommonSampleLibrary.LogFragment"
/>
<fragment
android:id="@+id/fragmentWithInferredType"
android:name="CommonSampleLibrary.LogFragment"
/>
</LinearLayout>
ezután a következő típus jön létre:
// Generated code
namespace Binding {
sealed class Main : global::Xamarin.Android.Design.LayoutBinding {
[global::Android.Runtime.PreserveAttribute (Conditional=true)]
public Main (
global::Android.App.Activity client,
global::Xamarin.Android.Design.OnLayoutItemNotFoundHandler itemNotFoundHandler = null)
: base (client, itemNotFoundHandler) {}
[global::Android.Runtime.PreserveAttribute (Conditional=true)]
public Main (
global::Android.Views.View client,
global::Xamarin.Android.Design.OnLayoutItemNotFoundHandler itemNotFoundHandler = null)
: base (client, itemNotFoundHandler) {}
Button __myButton;
public Button myButton => FindView (global::Xamarin.Android.Tests.CodeBehindFew.Resource.Id.myButton, ref __myButton);
CommonSampleLibrary.LogFragment __fragmentWithExplicitManagedType;
public CommonSampleLibrary.LogFragment fragmentWithExplicitManagedType =>
FindFragment (global::Xamarin.Android.Tests.CodeBehindFew.Resource.Id.fragmentWithExplicitManagedType, __fragmentWithExplicitManagedType, ref __fragmentWithExplicitManagedType);
global::Android.App.Fragment __fragmentWithInferredType;
public global::Android.App.Fragment fragmentWithInferredType =>
FindFragment (global::Xamarin.Android.Tests.CodeBehindFew.Resource.Id.fragmentWithInferredType, __fragmentWithInferredType, ref __fragmentWithInferredType);
}
}
A kötés alaptípusa Xamarin.Android.Design.LayoutBinding része az Androidhoz készült .NET osztálykódtárnak, hanem forrás formában az Androidhoz készült .NET-hez van szállítva, és a kötések használatakor automatikusan bekerül az alkalmazás buildjébe.
A generált kötéstípus a Activity példányok köré hozható létre, így az elrendezésfájlban erősen típusos hozzáférést biztosítva az azonosítókhoz.
// User-written code
partial class MainActivity : Activity {
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.Main);
var binding = new Binding.Main (this);
Button button = binding.myButton;
button.Click += delegate {
button.Text = $"{count++} clicks!";
};
}
}
A binding típusok a View példányok köré is felépíthetők, lehetővé téve az erősen gépelt hozzáférést az erőforrás-azonosítókhoz a nézeten vagy annak gyermekein belül.
var binding = new Binding.Main (some_view);
Hiányzó erőforrásazonosítók
A kötéstípusok még mindig FindViewById<T>()-t használnak a megvalósítás során. Ha a FindViewById<T>() visszaadja a null értéket, akkor az alapértelmezett viselkedés az, hogy a tulajdonság null helyett InvalidOperationException kivételt vált ki.
Ezt az alapértelmezett viselkedést felülírhatja egy hibakezelő delegált átadása a létrehozott kötésnek a példányosításkor:
// User-written code
partial class MainActivity : Activity {
Java.Lang.Object? OnLayoutItemNotFound (int resourceId, Type expectedViewType)
{
// Find and return the View or Fragment identified by `resourceId`
// or `null` if unknown
return null;
}
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.Main);
var binding = new Binding.Main (this, OnLayoutItemNotFound);
}
}
A OnLayoutItemNotFound() metódust akkor hívják meg, ha nem található View vagy Fragment erőforrás-azonosító.
A kezelőnek vissza kell adnia vagy a null-t, amely esetben a InvalidOperationException lesz dobva, vagy, lehetőség szerint, a View vagy Fragment példányt, amely megfelel a kezelőnek átadott azonosítónak. A visszaadott objektumnak a megfelelő Kötés tulajdonság típusának megfelelő típusúnak kell lennie. A visszaadott érték erre a típusra lesz vetve, így ha az objektum nem megfelelően van begépelve, kivételt küld a rendszer.
Code-Behind
Code-Behind magában foglalja egy partial osztály buildelési idejű létrehozását, amely az elrendezésfájl összes azonosítójának erősen típusos tulajdonságait tartalmazza.
Code-Behind a kötési mechanizmusra épül, miközben megköveteli, hogy az elrendezésfájlok engedélyezzék a Code-Behind generálást az új xamarin:classes XML-attribútum használatával, amely a létrehozandó teljes osztálynevek egy ;-vel elválasztott listája.
Az Android Layout fájl Resources\layout\Main.axml esetén:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools"
xamarin:classes="Example.MainActivity">
<Button android:id="@+id/myButton" />
<fragment
android:id="@+id/fragmentWithExplicitManagedType"
android:name="commonsamplelibrary.LogFragment"
xamarin:managedType="CommonSampleLibrary.LogFragment"
/>
<fragment
android:id="@+id/fragmentWithInferredType"
android:name="CommonSampleLibrary.LogFragment"
/>
</LinearLayout>
a buildeléskor a következő típus lesz létrehozva:
// Generated code
namespace Example {
partial class MainActivity {
Binding.Main __layout_binding;
public override void SetContentView (global::Android.Views.View view);
void SetContentView (global::Android.Views.View view,
global::Xamarin.Android.Design.LayoutBinding.OnLayoutItemNotFoundHandler onLayoutItemNotFound);
public override void SetContentView (global::Android.Views.View view, global::Android.Views.ViewGroup.LayoutParams @params);
void SetContentView (global::Android.Views.View view, global::Android.Views.ViewGroup.LayoutParams @params,
global::Xamarin.Android.Design.LayoutBinding.OnLayoutItemNotFoundHandler onLayoutItemNotFound);
public override void SetContentView (int layoutResID);
void SetContentView (int layoutResID,
global::Xamarin.Android.Design.LayoutBinding.OnLayoutItemNotFoundHandler onLayoutItemNotFound);
partial void OnSetContentView (global::Android.Views.View view, ref bool callBaseAfterReturn);
partial void OnSetContentView (global::Android.Views.View view, global::Android.Views.ViewGroup.LayoutParams @params, ref bool callBaseAfterReturn);
partial void OnSetContentView (int layoutResID, ref bool callBaseAfterReturn);
public Button myButton => __layout_binding?.myButton;
public CommonSampleLibrary.LogFragment fragmentWithExplicitManagedType => __layout_binding?.fragmentWithExplicitManagedType;
public global::Android.App.Fragment fragmentWithInferredType => __layout_binding?.fragmentWithInferredType;
}
}
Ez lehetővé teszi az erőforrás-azonosítók "intuitívabb" használatát az elrendezésen belül:
// User-written code
partial class MainActivity : Activity {
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.Main);
myButton.Click += delegate {
button.Text = $"{count++} clicks!";
};
}
}
A OnLayoutItemNotFound hibakezelő átadható az SetContentView tevékenység bármelyik túlterhelésének utolsó paramétereként.
// User-written code
partial class MainActivity : Activity {
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.Main, OnLayoutItemNotFound);
}
Java.Lang.Object? OnLayoutItemNotFound (int resourceId, Type expectedViewType)
{
// Find and return the View or Fragment identified by `resourceId`
// or `null` if unknown
return null;
}
}
Mivel Code-Behind részleges osztályokra támaszkodik, a részleges osztály összes deklarációját használniapartial class kell a deklarációban, ellenkező esetben cs0260 C#-fordítóhiba jön létre a létrehozáskor.
Testreszabás
A létrehozott kód mögötti típus mindig felülbírálja Activity.SetContentView()a paraméterek továbbítását, és alapértelmezés szerint mindig meghívja base.SetContentView(). Ha ez nem kívánatos, akkor az OnSetContentView()partial egyik metódust felül kell bírálni, a következő beállítással callBaseAfterReturnfalse:
// Generated code
namespace Example
{
partial class MainActivity {
partial void OnSetContentView (global::Android.Views.View view, ref bool callBaseAfterReturn);
partial void OnSetContentView (global::Android.Views.View view, global::Android.Views.ViewGroup.LayoutParams @params, ref bool callBaseAfterReturn);
partial void OnSetContentView (int layoutResID, ref bool callBaseAfterReturn);
}
}
Példa generált kódra
// Generated code
namespace Example
{
partial class MainActivity {
Binding.Main? __layout_binding;
public override void SetContentView (global::Android.Views.View view)
{
__layout_binding = new global::Binding.Main (view);
bool callBase = true;
OnSetContentView (view, ref callBase);
if (callBase) {
base.SetContentView (view);
}
}
void SetContentView (global::Android.Views.View view, global::Xamarin.Android.Design.LayoutBinding.OnLayoutItemNotFoundHandler onLayoutItemNotFound)
{
__layout_binding = new global::Binding.Main (view, onLayoutItemNotFound);
bool callBase = true;
OnSetContentView (view, ref callBase);
if (callBase) {
base.SetContentView (view);
}
}
public override void SetContentView (global::Android.Views.View view, global::Android.Views.ViewGroup.LayoutParams @params)
{
__layout_binding = new global::Binding.Main (view);
bool callBase = true;
OnSetContentView (view, @params, ref callBase);
if (callBase) {
base.SetContentView (view, @params);
}
}
void SetContentView (global::Android.Views.View view, global::Android.Views.ViewGroup.LayoutParams @params, global::Xamarin.Android.Design.LayoutBinding.OnLayoutItemNotFoundHandler onLayoutItemNotFound)
{
__layout_binding = new global::Binding.Main (view, onLayoutItemNotFound);
bool callBase = true;
OnSetContentView (view, @params, ref callBase);
if (callBase) {
base.SetContentView (view, @params);
}
}
public override void SetContentView (int layoutResID)
{
__layout_binding = new global::Binding.Main (this);
bool callBase = true;
OnSetContentView (layoutResID, ref callBase);
if (callBase) {
base.SetContentView (layoutResID);
}
}
void SetContentView (int layoutResID, global::Xamarin.Android.Design.LayoutBinding.OnLayoutItemNotFoundHandler onLayoutItemNotFound)
{
__layout_binding = new global::Binding.Main (this, onLayoutItemNotFound);
bool callBase = true;
OnSetContentView (layoutResID, ref callBase);
if (callBase) {
base.SetContentView (layoutResID);
}
}
partial void OnSetContentView (global::Android.Views.View view, ref bool callBaseAfterReturn);
partial void OnSetContentView (global::Android.Views.View view, global::Android.Views.ViewGroup.LayoutParams @params, ref bool callBaseAfterReturn);
partial void OnSetContentView (int layoutResID, ref bool callBaseAfterReturn);
public Button myButton => __layout_binding?.myButton;
public CommonSampleLibrary.LogFragment fragmentWithExplicitManagedType => __layout_binding?.fragmentWithExplicitManagedType;
public global::Android.App.Fragment fragmentWithInferredType => __layout_binding?.fragmentWithInferredType;
}
}
Elrendezés XML-attribútumai
Számos új elrendezési XML-attribútum szabályozza a kötés és Code-Behind viselkedését, amelyek az xamarin XML-névtérben (xmlns:xamarin="http://schemas.xamarin.com/android/xamarin/tools") találhatók.
Ezek közé tartoznak:
xamarin:classes
Az xamarin:classes XML-attribútum a Code-Behind részeként használható annak meghatározására, hogy mely típusokat kell létrehozni.
Az xamarin:classes XML-attribútum a ;létrehozandó teljes osztálynevek elválasztott listáját tartalmazza.
xamarin:managedType
Az xamarin:managedType elrendezési attribútum a felügyelt típus explicit megadásával teszi elérhetővé a kötött azonosítót. Ha nincs megadva, a típust a deklarálási környezetből inferáljuk, például: <Button/> egy Android.Widget.Button eredményez, és <fragment/> egy Android.App.Fragment eredményez.
Az xamarin:managedType attribútum explicitebb típusdeklarációkat tesz lehetővé.
Felügyelt típusleképezés
Elég gyakori, hogy widgetneveket használnak az általuk kapott Java-csomag alapján, és ugyanilyen gyakran az ilyen típusú felügyelt .NET-névnek más (.NET-stílusú) neve lesz a felügyelt országban. A kódgenerátor számos nagyon egyszerű módosítást hajthat végre, hogy megpróbáljon megegyezni a kóddal, például:
A típusnévtér és a név összes összetevőjének nagybetűsítése. Például
java.package.myButtonválhatnaJava.Package.MyButtonA típusnévtér kétbetűs összetevőinek nagybetűsítése. Például
android.os.SomeTypeválhatnaAndroid.OS.SomeTypeKeressen több olyan, nehezen kódolt névteret, amely ismert leképezésekkel rendelkezik. A lista jelenleg a következő leképezéseket tartalmazza:
-
android.view–>Android.Views -
com.actionbarsherlock–>ABSherlock -
com.actionbarsherlock.widget–>ABSherlock.Widget -
com.actionbarsherlock.view–>ABSherlock.View -
com.actionbarsherlock.app–>ABSherlock.App
-
A belső táblákban számos, nehezen kódolt típust kereshet. A lista jelenleg a következő típusokat tartalmazza:
-
WebView–>Android.Webkit.WebView
-
A rögzített névtér előtagjainak sávszáma. A lista jelenleg a következő előtagokat tartalmazza:
com.google.
Ha azonban a fenti kísérletek sikertelenek, módosítania kell az elrendezést, amely egy ilyen leképezetlen típusú widgetet használ ahhoz, hogy az XML-névtér-deklarációt az elrendezés gyökéreleméhez és a xamarin leképezést igénylő elemhez is xamarin:managedType hozzáadja. Ilyenek például a következők:
<fragment
android:id="@+id/log_fragment"
android:name="commonsamplelibrary.LogFragment"
xamarin:managedType="CommonSampleLibrary.LogFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
A natív típus CommonSampleLibrary.LogFragmenttípusát fogja használnicommonsamplelibrary.LogFragment.
Elkerülheti az XML-névtér deklarációjának és az attribútumnak a xamarin:managedType hozzáadását úgy, hogy egyszerűen elnevezi a típust a felügyelt nevével, például a fenti töredék az alábbiak szerint újra kiírható:
<fragment
android:name="CommonSampleLibrary.LogFragment"
android:id="@+id/secondary_log_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Töredékek: különleges eset
Az Android-ökoszisztéma jelenleg a widget két különböző implementációját Fragment támogatja:
-
Android.App.FragmentA "klasszikus" Fragment az androidos alaprendszerrel került kiadásra -
AndroidX.Fragment.App.Fragmentelemet,Xamarin.AndroidX.FragmentNuGet-csomag.
Ezek az osztályok nem kompatibilisek egymással, ezért különös figyelmet kell fordítani az elrendezésfájlok elemeinek <fragment> kötéskódjának létrehozásakor. Az Androidhoz készült .NET-nek az Fragment alapértelmezett implementációt kell választania, ha az <fragment> elem nem rendelkezik megadott (felügyelt vagy egyéb) típussal. A kötéskód-generátor a következőt használja:
$(AndroidFragmentType) MSBuild tulajdonság erre a célra. A tulajdonság felülbírálható a felhasználó által az alapértelmezett típustól eltérő típus megadásához. A tulajdonság alapértelmezés szerint Android.App.Fragment értékre van állítva, és az AndroidX NuGet-csomagok felülírják.
Ha a létrehozott kód nem épül fel, az elrendezésfájlt módosítani kell a szóban forgó töredék rugalmas típusának megadásával.
Kód mögötti elrendezés kiválasztása és feldolgozása
Szelekció
Alapértelmezés szerint a kód mögötti generáció le van tiltva. Az összes elrendezés feldolgozásának engedélyezéséhez bármely Resource\layout* könyvtárban, amely legalább egyetlen elemet tartalmaz az //*/@android:id attribútummal, állítsa az $(AndroidGenerateLayoutBindings) MSBuild tulajdonságot True az msbuild parancssorában:
dotnet build -p:AndroidGenerateLayoutBindings=true MyProject.csproj
vagy a .csproj fájlban:
<PropertyGroup>
<AndroidGenerateLayoutBindings>true</AndroidGenerateLayoutBindings>
</PropertyGroup>
Alternatív megoldásként letilthatja a háttérkódot globálisan, és csak bizonyos fájlok esetében engedélyezheti. Ha egy adott .axml fájlhoz szeretné engedélyezni a "Code-Behind" funkciót, módosítsa a fájlt úgy, hogy a build művelet je legyen
@(AndroidBoundLayout) a .csproj fájl szerkesztésének módosításával, és cserélje le a AndroidResource a AndroidBoundLayout-re:
<!-- This -->
<AndroidResource Include="Resources\layout\Main.axml" />
<!-- should become this -->
<AndroidBoundLayout Include="Resources\layout\Main.axml" />
Processing
Az elrendezések név szerint vannak csoportosítva, és a különbözőResource\layout* könyvtárak hasonló nevű sablonjai egyetlen csoportot alkotnak. Ezek a csoportok úgy vannak feldolgozva, mintha egyetlen elrendezés lennének. Lehetséges, hogy ebben az esetben típusütközés lesz az ugyanazon csoporthoz tartozó különböző elrendezésekben található két widget között. Ebben az esetben a létrehozott tulajdonság nem tudja pontosan a widget típusát, hanem egy "elpusztult" típust. A romlás az alábbi algoritmust követi:
Ha az ütköző vezérlők
Viewmindegyike származékos, a tulajdonság típusaAndroid.Views.ViewHa az ütköző típusok
Fragmentmindegyike származékos, a tulajdonságtípusAndroid.App.FragmentHa az ütköző widgetek mind a
View, mind aFragmenttartalmazzák, a tulajdonság típusaglobal::System.Objectlesz.
Generált kód
Ha érdekli, hogyan néz ki a létrehozott kód az elrendezéseihez, tekintse meg a obj\$(Configuration)\generated mappát a megoldáskönyvtárában.