@@ -11,28 +11,45 @@ dateupdated: 2018-01-29
1111Xamarin.Android supports the auto generation of "Code Behind" classes. These classes
1212can reduce the amount code a developer writes. You can end up replacing code like
1313
14- SetContentView (Resource.Layout.Main);
15- var button = FindViewById<Button> (Resource.Id.myButton);
16- button.Click += delegate {
17- };
14+ ``` csharp
15+ SetContentView (Resource .Layout .Main );
16+ var button = FindViewById <Button > (Resource .Id .myButton );
17+ button .Click += delegate {
18+ };
19+ ```
1820
1921with
2022
21- InitializeContentView ();
22- myButton.Click += delegate {
23- };
23+ ``` csharp
24+ InitializeContentView ();
25+ myButton .Click += delegate {
26+ };
27+ ```
2428
29+ or, with nested layouts:
30+
31+ ``` csharp
32+ InitializeContentView ();
33+ myParentLayout .myButton .Widget .Click += delegate {
34+ };
35+ ```
2536
2637<a name =" " class =" injected " /></a >
2738
2839# Preparing to use Code Behind
2940
3041In order to make use of this new feature there are a few changes which are required.
31- An axml/xml file that you want to associate with an activity needs to be modified to
32- include a few extra xml attributes on the root layout element.
42+ An `` axml/xml `` file that you want to associate with an activity needs to be modified to
43+ include a few extra xml attributes on the root layout element.
44+
45+ Additionally, ** only*** elements which have the ` android:id ` attribute will be accessible via
46+ the generated code.
47+
3348
34- xmlns:tools="http://schemas.xamarin.com/android/tools"
35- tools:class="$(Namespace).$(ClassName)"
49+ ``` xml
50+ xmlns:tools="http://schemas.xamarin.com/android/tools"
51+ tools:class="$(Namespace).$(ClassName)"
52+ ```
3653
3754The ` class ` attribute defines the Namespace and ClassName of the code which will be
3855generated. For example if you have a layout for your ` MainActivity ` you would set
@@ -42,35 +59,46 @@ qualified name, not just the class name on its own.
4259The next thing we need to do is to make the ` MainActivity ` a ` partial ` class. This
4360allows the genereted code to extend the current class which you have written.
4461So
45- public class MainActivity : Activity {
46- }
62+
63+ ``` csharp
64+ public class MainActivity : Activity {
65+ }
66+ ```
4767
4868will become
4969
50- public partial class MainActivity : Activity {
51- }
70+ ``` csharp
71+ public partial class MainActivity : Activity {
72+ }
73+ ```
5274
5375You then need to make sure you initialize the layout properties by calling
5476` InitializeContentView () ` in the ` OnCreate() ` method of your activity.
5577
56- protected override void OnCreate (Bundle bundle)
57- {
58- base.OnCreate (bundle);
59- InitializeContentView ();
60- }
78+ ``` csharp
79+ protected override void OnCreate (Bundle bundle )
80+ {
81+ base .OnCreate (bundle );
82+ InitializeContentView ();
83+ }
84+ ```
6185
6286For those of you familiar with System.Windows.Forms this is akin
6387to ` InitializeComponent ` . Once this has been done you can now access
6488your layout items via the properties.
6589
66- myButton.Click += delegate {
67- };
90+ ``` csharp
91+ myButton .Click += delegate {
92+ };
93+ ```
6894
6995There is a partial method available which can be implemented to handle
7096situations where the View is not found. The method is
7197
72- void OnLayoutViewNotFound<T> (int resourceId, ref T type)
73- where T : global::Android.Views.View;
98+ ``` csharp
99+ void OnLayoutViewNotFound <T > (int resourceId , ref T type )
100+ where T : global :: Android .Views .View ;
101+ ```
74102
75103If ` FindViewById ` returns ` null ` then the ` OnLayoutViewNotFound ` method
76104will be called (if it is implemented). This is done BEFORE we throw the
@@ -79,6 +107,96 @@ situation in a manner which fits the app they are writing. For example
79107you might want to switch to a backup view, or just log some additional
80108diagnostic information.
81109
110+ Another partial method exists to handle fragments:
111+
112+ ``` csharp
113+ void OnLayoutFragmentNotFound <T > (int resourceId , ref T type )
114+ where T : global :: Android .App .Fragment ;
115+ ```
116+
117+ It works in exactly the same way as ` OnLayoutViewNotFound ` above, just for fragments.
118+
119+ ## Generated code structure
120+
121+ The generated code-behind is laid out in a hierarchical fashion, reflecting the parent-child
122+ relationship found in the layout file. The way it is done is that each element which has any
123+ child elements ** with** the ` android:id ` attribute (that is, ones which will also have code
124+ generated for them) will have a nested class generated for it which will have a property for
125+ each child element as well as the ` Widget ` property which refers to this element's actual
126+ Android widget/view. Each element which does ** not** have any child elements with the
127+ ` android:id ` attribute, however, will become a * leaf node* and will have an associated property
128+ in its parent widget's class directly typed to the actual Android type (e.g. ` TextView ` ) instead
129+ of the class described before. For instance, given this layout:
130+
131+ ``` xml
132+ <LinearLayout xmlns : android =" http://schemas.android.com/apk/res/android" xmlns : tools =" http://schemas.xamarin.com/android/tools"
133+ tools : class =" MyActivity" >
134+ <ScrollView android : id =" @+id/myScrollView" >
135+ <TextView android : id =" @+id/myTextView" />
136+ </ScrollView >
137+ </LinearLayout >
138+ ```
139+
140+ The code-behind will have this rough structure (class names are different to keep the documentation clear):
141+
142+ ``` csharp
143+ myScrollView_Class myScrollView {
144+ get { return new myScrollView_Class (this ); }
145+ }
146+
147+ class myScrollView_Class
148+ {
149+ public ScrollView Widget {
150+ get { /* ... */ }
151+ }
152+
153+ public TextView myTextView {
154+ get { /* ... */ }
155+ }
156+
157+ public myScrollView_Class (MyActivity parent ) {}
158+ }
159+ ```
160+
161+ So in order to access the widgets you'd use code similar to:
162+
163+ ``` csharp
164+ InitializeContentView ();
165+ myScrollView .Widget .Fling (100 );
166+ myScrollView .myTextView .AutoSizeMaxTextSize = 40 ;
167+ ```
168+
169+ ## Managed types
170+
171+ By default each element for which we generate code-behind has its managed type set to
172+ its local name, for instance
173+
174+ ``` xml
175+ <TextView android : id =" " @+id/textView" />
176+ ```
177+
178+ Will generate a property named `textView` of type `TextView`. It works fine in most cases
179+ but sometimes you might find code which either refers to a custom widget using the package
180+ name or a fragment which uses the case-insensitive `android:name` attribute syntax, for
181+ instance:
182+
183+ ```xml
184+ <fragment
185+ android:name=" commonsamplelibrary.LogFragment"
186+ android:id=" @+id/log_fragment" />
187+ ```
188+
189+ In this case the generated property would have the managed type `commonsamplelibrary.LogFragment`,
190+ however the actual managed type fully qualified name is `CommonSampleLibrary.LogFragment` and thus
191+ the generated code would fail to compile. The solution is to add the `tools:managedType` attribute
192+ which specifies the element's (all elements support this attribute) managed type.
193+
194+ One may wonder why we didn't reuse the `tools:class` attribute to specify the managed type? It is
195+ because that attribute is used to specify the code-behind partial class name on the root element of
196+ the layout and should the element had the `android:id` attribute present we'd end up with generated
197+ code that would use the **activity** type for the element's associated property instead of its
198+ actual type and the code wouldn't build.
199+
82200# How it works
83201
84202There are a couple of new MSBuild Tasks which generate the code behind.
0 commit comments