Xamarin.Forms中 Navigation,NavigationPage详解

1.Xamarin Forms下有四个成员类:Element,VisualElement,Page,NavigationPage

基类为Element,继承的子类分别是VisualElement,Page,NavigationPage.

2.Navigation 为VisualElement的一个成员对象,该对象是INavigation接口类型的。

3.INavigation接口中有5个方法,如下

namespace Xamarin.Forms
{
    public interface INavigation
    {
        //
        // Methods
        //
        Task<Page> PopAsync ();

        Task<Page> PopModalAsync ();

        Task PopToRootAsync ();

        Task PushAsync (Page page);

        Task PushModalAsync (Page page);
    }
}

4.NavigationPage下有PopAsync(),PopToRootAsync(),PushAsync(Page)的具体实现。

5.我们平时使用的时候会在App.cs 中使用“return new NavigationPage(new HomePage())”这种方式来启动一个可以包含子页面的页面。

而在HomePage页面中我们使用“Navigation.PushAsync(new NextPage())”来启动子页面。

Page对象派生出来的子类有:ContentPage,TabbedPage,NavigationPage,CarouselPage,MasterDetailPage 5大常用页面。

6.有的时候我们可能产生疑问,INavigation的5个方法的具体实现在哪里?(答案在第7部分)

我们可以看下这几个Page派生的类中有哪些东西,如下图:标记部分需要我们仔细查看

NavigationPage:

ContentPage:

TabbedPage:

CarouselPage:

MasterDetailPage:

7.我们先来看下VisualElement的具体内容:

View Code

这个对象中有一个BindableProperty对象NavigationProperty

public static readonly BindableProperty NavigationProperty = VisualElement.NavigationPropertyKey.BindableProperty;

 其实它下面还有一个对象,是个静态的NavigationPropertyKey,内容如下:

internal static readonly BindablePropertyKey NavigationPropertyKey = BindableProperty.CreateReadOnly ("Navigation", typeof(INavigation), typeof(VisualElement), null, BindingMode.OneWayToSource, null, null, null, null);

这个对象是自创建的,就是说是在VisualElement中这个对象实例话后就会有的,ContentPage继承了Page,Page继承了VisualElement,所以说这个对象是在所有继承 Page对象的子类实例话后就存在的。  

VisualElement 中 Navigation对象的代码:

using System;

public INavigation Navigation {
	get {
		return (INavigation)base.GetValue (VisualElement.NavigationProperty);
	}
	internal set {
		base.SetValue (VisualElement.NavigationPropertyKey, value);
	}
}

这里的base是指,父类"Element"的父类"BindableObject"中的方法。

接下来,我们来看下BindableObject是什么东西?BindableObject的public members如下

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Reflection;
  5 using System.Runtime.CompilerServices;
  6 
  7 namespace Xamarin.Forms
  8 {
  9     public abstract class BindableObject : INotifyPropertyChanged
 10     {
 11         //
 12         // Static Fields
 13         //
 14         public static readonly BindableProperty BindingContextProperty = BindableProperty.Create ("BindingContext", typeof(object), typeof(BindableObject), null, BindingMode.OneWay, null, new BindableProperty.BindingPropertyChangedDelegate (BindableObject.BindingContextPropertyBindingPropertyChanged), null, null, new BindableProperty.BindablePropertyBindingChanging (BindableObject.BindingContextPropertyBindingChanging));
 15 
 16         //
 17         // Properties
 18         //
 19         public object BindingContext {
 20             get {
 21                 return this.inheritedContext ?? this.GetValue (BindableObject.BindingContextProperty);
 22             }
 23             set {
 24                 this.SetValue (BindableObject.BindingContextProperty, value);
 25             }
 26         }
 27 
 28         //
 29         // Constructors
 30         //
 31         protected BindableObject ()
 32         {
 33             this.bindings = new Dictionary<BindableProperty, BindingBase> (4);
 34             this.values = new Dictionary<BindableProperty, object> (4);
 35             this.manuallySetValues = new List<BindableProperty> (4);
 36             this.delayedSetters = new Dictionary<BindableProperty, Queue<Action>> (2);
 37             base..ctor ();
 38         }
 39 
 40         //
 41         // Static Methods
 42         //
 43         private static void BindingContextPropertyBindingChanging (BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
 44         {
 45             object context = bindable.inheritedContext;
 46             Binding binding = oldBindingBase as Binding;
 47             Binding binding2 = newBindingBase as Binding;
 48             if (context == null && binding != null) {
 49                 context = binding.Context;
 50             }
 51             if (context != null && binding2 != null) {
 52                 binding2.Context = context;
 53             }
 54         }
 55 
 56         private static void BindingContextPropertyBindingPropertyChanged (BindableObject bindable, object oldvalue, object newvalue)
 57         {
 58             object obj = bindable.inheritedContext;
 59             bindable.inheritedContext = null;
 60             bindable.ApplyBindings (obj ?? oldvalue);
 61             bindable.OnBindingContextChanged ();
 62         }
 63 
 64         protected static void SetInheritedBindingContext (BindableObject bindable, object value)
 65         {
 66             if (bindable.HasManuallySetValue (BindableObject.BindingContextProperty)) {
 67                 return;
 68             }
 69             object bindingContext = bindable.BindingContext;
 70             BindingBase bindingBase;
 71             if (bindable.bindings.TryGetValue (BindableObject.BindingContextProperty, out bindingBase)) {
 72                 ((Binding)bindingBase).Context = value;
 73                 bindable.inheritedContext = null;
 74             }
 75             else {
 76                 if (object.ReferenceEquals (bindable.BindingContext, value)) {
 77                     return;
 78                 }
 79                 bindable.inheritedContext = value;
 80             }
 81             bindable.ApplyBindings (bindingContext);
 82             bindable.OnBindingContextChanged ();
 83         }
 84 
 85         //
 86         // Methods
 87         //
 88         protected void ApplyBindings (object oldContext = null)
 89         {
 90             foreach (KeyValuePair<BindableProperty, BindingBase> current in this.bindings) {
 91                 if (oldContext != null) {
 92                     current.Value.Unapply ();
 93                 }
 94                 current.Value.Apply (this.BindingContext, this, current.Key);
 95             }
 96         }
 97 
 98         public void ClearValue (BindableProperty property)
 99         {
100             this.ClearValue (property, true);
101         }
102 
103         public void ClearValue (BindablePropertyKey propertyKey)
104         {
105             if (propertyKey == null) {
106                 throw new ArgumentNullException ("propertyKey");
107             }
108             this.ClearValue (propertyKey.BindableProperty, false);
109         }
110 
111         private void ClearValue (BindableProperty property, bool checkaccess)
112         {
113             if (property == null) {
114                 throw new ArgumentNullException ("property");
115             }
116             if (checkaccess && property.IsReadOnly) {
117                 throw new InvalidOperationException (string.Format ("The BindableProperty "{0}" is readonly.", new object[] {
118                     property.PropertyName
119                 }));
120             }
121             object value = this.GetValue (property);
122             object defaultValue = property.DefaultValue;
123             bool flag = object.Equals (value, defaultValue);
124             if (!flag) {
125                 if (property.PropertyChanging != null) {
126                     property.PropertyChanging (this, value, property.DefaultValue);
127                 }
128                 this.OnPropertyChanging (property.PropertyName);
129             }
130             this.manuallySetValues.Remove (property);
131             this.values.Remove (property);
132             if (!flag) {
133                 this.OnPropertyChanged (property.PropertyName);
134                 if (property.PropertyChanged != null) {
135                     property.PropertyChanged (this, value, property.DefaultValue);
136                 }
137             }
138         }
139 
140         internal bool GetIsBound (BindableProperty targetProperty)
141         {
142             if (targetProperty == null) {
143                 throw new ArgumentNullException ("targetProperty");
144             }
145             return this.bindings.ContainsKey (targetProperty);
146         }
147 
148         public object GetValue (BindableProperty property)
149         {
150             if (property == null) {
151                 throw new ArgumentNullException ("property");
152             }
153             object defaultValue;
154             if (!this.values.TryGetValue (property, out defaultValue)) {
155                 defaultValue = property.DefaultValue;
156             }
157             return defaultValue;
158         }
159 
160         private bool HasManuallySetValue (BindableProperty property)
161         {
162             if (property == null) {
163                 throw new ArgumentNullException ("property");
164             }
165             return this.manuallySetValues.Contains (property);
166         }
167 
168         protected virtual void OnBindingContextChanged ()
169         {
170             EventHandler bindingContextChanged = this.BindingContextChanged;
171             if (bindingContextChanged != null) {
172                 bindingContextChanged (this, EventArgs.Empty);
173             }
174         }
175 
176         protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null)
177         {
178             PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
179             if (propertyChanged != null) {
180                 propertyChanged (this, new PropertyChangedEventArgs (propertyName));
181             }
182         }
183 
184         protected virtual void OnPropertyChanging ([CallerMemberName] string propertyName = null)
185         {
186             PropertyChangingEventHandler propertyChanging = this.PropertyChanging;
187             if (propertyChanging != null) {
188                 propertyChanging (this, new PropertyChangingEventArgs (propertyName));
189             }
190         }
191 
192         public void RemoveBinding (BindableProperty property)
193         {
194             if (property == null) {
195                 throw new ArgumentNullException ("property");
196             }
197             BindingBase bindingBase;
198             if (!this.bindings.TryGetValue (property, out bindingBase)) {
199                 return;
200             }
201             bindingBase.Unapply ();
202             if (property.BindingChanging != null) {
203                 property.BindingChanging (this, bindingBase, null);
204             }
205             this.bindings.Remove (property);
206         }
207 
208         public void SetBinding (BindableProperty targetProperty, BindingBase binding)
209         {
210             if (targetProperty == null) {
211                 throw new ArgumentNullException ("targetProperty");
212             }
213             if (binding == null) {
214                 throw new ArgumentNullException ("binding");
215             }
216             BindingBase bindingBase;
217             if (this.bindings.TryGetValue (targetProperty, out bindingBase)) {
218                 bindingBase.Unapply ();
219             }
220             this.bindings [targetProperty] = binding;
221             if (targetProperty.BindingChanging != null) {
222                 targetProperty.BindingChanging (this, bindingBase, binding);
223             }
224             binding.Apply (this.BindingContext, this, targetProperty);
225         }
226 
227         private void SetValue (BindableProperty property, object value, bool checkaccess)
228         {
229             if (property == null) {
230                 throw new ArgumentNullException ("property");
231             }
232             if (checkaccess && property.IsReadOnly) {
233                 throw new InvalidOperationException (string.Format ("The BindableProperty "{0}" is readonly.", new object[] {
234                     property.PropertyName
235                 }));
236             }
237             if (!this.manuallySetValues.Contains (property)) {
238                 this.manuallySetValues.Add (property);
239             }
240             this.SetValueCore (property, value, true, false, checkaccess);
241         }
242 
243         public void SetValue (BindablePropertyKey propertyKey, object value)
244         {
245             if (propertyKey == null) {
246                 throw new ArgumentNullException ("propertyKey");
247             }
248             this.SetValue (propertyKey.BindableProperty, value, false);
249         }
250 
251         public void SetValue (BindableProperty property, object value)
252         {
253             this.SetValue (property, value, true);
254         }
255 
256         private void SetValueActual (BindableProperty property, object value, bool currentlyApplying, bool clearBindings, bool raiseOnEqual)
257         {
258             object defaultValue;
259             if (!this.values.TryGetValue (property, out defaultValue)) {
260                 defaultValue = property.DefaultValue;
261             }
262             bool flag = object.Equals (value, defaultValue);
263             if (!flag || raiseOnEqual) {
264                 if (property.PropertyChanging != null) {
265                     property.PropertyChanging (this, defaultValue, value);
266                 }
267                 this.OnPropertyChanging (property.PropertyName);
268                 this.values [property] = value;
269             }
270             BindingBase bindingBase;
271             if (this.bindings.TryGetValue (property, out bindingBase) && clearBindings && bindingBase.GetRealizedMode (property) == BindingMode.OneWay) {
272                 this.RemoveBinding (property);
273             }
274             if (!flag || raiseOnEqual) {
275                 if (bindingBase != null && !currentlyApplying) {
276                     this.applying = true;
277                     bindingBase.Apply (true);
278                     this.applying = false;
279                 }
280                 this.OnPropertyChanged (property.PropertyName);
281                 if (property.PropertyChanged != null) {
282                     property.PropertyChanged (this, defaultValue, value);
283                 }
284             }
285         }
286 
287         internal void SetValueCore (BindableProperty property, object value, bool clearBindings, bool raiseOnEqual = false, bool checkaccess = true)
288         {
289             if (property == null) {
290                 throw new ArgumentNullException ("property");
291             }
292             if (checkaccess && property.IsReadOnly) {
293                 return;
294             }
295             if (value != null && !property.ReturnType.IsInstanceOfType (value)) {
296                 MethodInfo runtimeMethod = property.ReturnType.GetRuntimeMethod ("op_Implicit", new Type[] {
297                     value.GetType ()
298                 });
299                 if (runtimeMethod == null || runtimeMethod.ReturnType != property.ReturnType) {
300                     Log.Warning ("SetValue", "Can not convert {0} to type '{1}'", new object[] {
301                         value,
302                         property.ReturnType
303                     });
304                     return;
305                 }
306                 value = runtimeMethod.Invoke (null, new object[] {
307                     value
308                 });
309             }
310             if (property.ValidateValue != null && !property.ValidateValue (this, value)) {
311                 throw new ArgumentException ("Value was an invalid value for " + property.PropertyName, "value");
312             }
313             if (property.CoerceValue != null) {
314                 value = property.CoerceValue (this, value);
315             }
316             bool currentlyApplying = this.applying;
317             Queue<Action> queue;
318             if (this.delayedSetters.TryGetValue (property, out queue)) {
319                 queue.Enqueue (delegate {
320                     this.SetValueActual (property, value, currentlyApplying, clearBindings, raiseOnEqual);
321                 });
322                 return;
323             }
324             queue = new Queue<Action> ();
325             this.delayedSetters.Add (property, queue);
326             this.SetValueActual (property, value, currentlyApplying, clearBindings, raiseOnEqual);
327             while (queue.Count > 0) {
328                 Action action = queue.Dequeue ();
329                 action ();
330             }
331             this.delayedSetters.Remove (property);
332         }
333 
334         protected void UnapplyBindings ()
335         {
336             foreach (BindingBase current in this.bindings.Values) {
337                 current.Unapply ();
338             }
339         }
340 
341         //
342         // Events
343         //
344         public event PropertyChangingEventHandler PropertyChanging;
345 
346         public event PropertyChangedEventHandler PropertyChanged;
347 
348         public event EventHandler BindingContextChanged;
349     }
350 }
View Code

 其中有必要说下BindableProperty这个对象,它的public memebers 如下

  1 using System;
  2 using System.Diagnostics;
  3 using System.Linq.Expressions;
  4 using System.Reflection;
  5 
  6 namespace Xamarin.Forms
  7 {
  8     [DebuggerDisplay ("{PropertyName}")]
  9     public sealed class BindableProperty
 10     {
 11         internal delegate void BindablePropertyBindingChanging (BindableObject bindable, BindingBase oldValue, BindingBase newValue);
 12 
 13         public delegate void BindingPropertyChangedDelegate (BindableObject bindable, object oldValue, object newValue);
 14 
 15         public delegate void BindingPropertyChangedDelegate<TPropertyType> (BindableObject bindable, TPropertyType oldValue, TPropertyType newValue);
 16 
 17         public delegate void BindingPropertyChangingDelegate<TPropertyType> (BindableObject bindable, TPropertyType oldValue, TPropertyType newValue);
 18 
 19         public delegate void BindingPropertyChangingDelegate (BindableObject bindable, object oldValue, object newValue);
 20 
 21         public delegate object CoerceValueDelegate (BindableObject bindable, object value);
 22 
 23         public delegate TPropertyType CoerceValueDelegate<TPropertyType> (BindableObject bindable, TPropertyType value);
 24 
 25         public delegate bool ValidateValueDelegate (BindableObject bindable, object value);
 26 
 27         public delegate bool ValidateValueDelegate<TPropertyType> (BindableObject bindable, TPropertyType value);
 28 
 29         //
 30         // Properties
 31         //
 32         internal BindableProperty.BindablePropertyBindingChanging BindingChanging {
 33             get;
 34             private set;
 35         }
 36 
 37         internal BindableProperty.CoerceValueDelegate CoerceValue {
 38             get;
 39             private set;
 40         }
 41 
 42         public Type DeclaringType {
 43             get;
 44             private set;
 45         }
 46 
 47         public BindingMode DefaultBindingMode {
 48             get;
 49             private set;
 50         }
 51 
 52         public object DefaultValue {
 53             get;
 54             private set;
 55         }
 56 
 57         public bool IsReadOnly {
 58             get;
 59             private set;
 60         }
 61 
 62         internal BindableProperty.BindingPropertyChangedDelegate PropertyChanged {
 63             get;
 64             private set;
 65         }
 66 
 67         internal BindableProperty.BindingPropertyChangingDelegate PropertyChanging {
 68             get;
 69             private set;
 70         }
 71 
 72         public string PropertyName {
 73             get;
 74             private set;
 75         }
 76 
 77         public Type ReturnType {
 78             get;
 79             private set;
 80         }
 81 
 82         internal BindableProperty.ValidateValueDelegate ValidateValue {
 83             get;
 84             private set;
 85         }
 86 
 87         //
 88         // Constructors
 89         //
 90         private BindableProperty (string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay, BindableProperty.ValidateValueDelegate validateValue = null, BindableProperty.BindingPropertyChangedDelegate propertyChanged = null, BindableProperty.BindingPropertyChangingDelegate propertyChanging = null, BindableProperty.CoerceValueDelegate coerceValue = null, BindableProperty.BindablePropertyBindingChanging bindingChanging = null, bool isReadOnly = false)
 91         {
 92             if (propertyName == null) {
 93                 throw new ArgumentNullException ("propertyName");
 94             }
 95             if (object.ReferenceEquals (returnType, null)) {
 96                 throw new ArgumentNullException ("returnType");
 97             }
 98             if (object.ReferenceEquals (declaringType, null)) {
 99                 throw new ArgumentNullException ("declaringType");
100             }
101             if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay) {
102                 throw new ArgumentException ("Not a valid type of BindingMode", "defaultBindingMode");
103             }
104             if (defaultValue == null && Nullable.GetUnderlyingType (returnType) == null && returnType.GetTypeInfo ().IsValueType) {
105                 throw new ArgumentException ("Not a valid default value", "defaultValue");
106             }
107             if (defaultValue != null && !returnType.IsInstanceOfType (defaultValue)) {
108                 throw new ArgumentException ("Default value did not match return type", "defaultValue");
109             }
110             if (defaultBindingMode == BindingMode.Default) {
111                 defaultBindingMode = BindingMode.OneWay;
112             }
113             this.PropertyName = propertyName;
114             this.ReturnType = returnType;
115             this.DeclaringType = declaringType;
116             this.DefaultValue = defaultValue;
117             this.DefaultBindingMode = defaultBindingMode;
118             this.PropertyChanged = propertyChanged;
119             this.PropertyChanging = propertyChanging;
120             this.ValidateValue = validateValue;
121             this.CoerceValue = coerceValue;
122             this.BindingChanging = bindingChanging;
123             this.IsReadOnly = isReadOnly;
124         }
125 
126         //
127         // Static Methods
128         //
129         internal static BindableProperty Create (string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, BindableProperty.ValidateValueDelegate validateValue, BindableProperty.BindingPropertyChangedDelegate propertyChanged, BindableProperty.BindingPropertyChangingDelegate propertyChanging, BindableProperty.CoerceValueDelegate coerceValue, BindableProperty.BindablePropertyBindingChanging bindingChanging)
130         {
131             return new BindableProperty (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging, false);
132         }
133 
134         internal static BindableProperty Create<TDeclarer, TPropertyType> (Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode, BindableProperty.ValidateValueDelegate<TPropertyType> validateValue, BindableProperty.BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindableProperty.BindingPropertyChangingDelegate<TPropertyType> propertyChanging, BindableProperty.CoerceValueDelegate<TPropertyType> coerceValue, BindableProperty.BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false) where TDeclarer : BindableObject
135         {
136             if (getter == null) {
137                 throw new ArgumentNullException ("getter");
138             }
139             Expression expression = getter.Body;
140             UnaryExpression unaryExpression = expression as UnaryExpression;
141             if (unaryExpression != null) {
142                 expression = unaryExpression.Operand;
143             }
144             MemberExpression memberExpression = expression as MemberExpression;
145             if (memberExpression == null) {
146                 throw new ArgumentException ("getter must be a MemberExpression", "getter");
147             }
148             PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member;
149             BindableProperty.ValidateValueDelegate validateValue2 = null;
150             BindableProperty.BindingPropertyChangedDelegate propertyChanged2 = null;
151             BindableProperty.BindingPropertyChangingDelegate propertyChanging2 = null;
152             BindableProperty.CoerceValueDelegate coerceValue2 = null;
153             if (validateValue != null) {
154                 validateValue2 = ((BindableObject bindable, object value) => validateValue (bindable, (TPropertyType)((object)value)));
155             }
156             if (propertyChanged != null) {
157                 propertyChanged2 = delegate (BindableObject bindable, object oldValue, object newValue) {
158                     propertyChanged (bindable, (TPropertyType)((object)oldValue), (TPropertyType)((object)newValue));
159                 };
160             }
161             if (propertyChanging != null) {
162                 propertyChanging2 = delegate (BindableObject bindable, object oldValue, object newValue) {
163                     propertyChanging (bindable, (TPropertyType)((object)oldValue), (TPropertyType)((object)newValue));
164                 };
165             }
166             if (coerceValue != null) {
167                 coerceValue2 = ((BindableObject bindable, object value) => coerceValue (bindable, (TPropertyType)((object)value)));
168             }
169             return new BindableProperty (propertyInfo.Name, propertyInfo.PropertyType, typeof(TDeclarer), defaultValue, defaultBindingMode, validateValue2, propertyChanged2, propertyChanging2, coerceValue2, bindingChanging, isReadOnly);
170         }
171 
172         public static BindableProperty Create (string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay, BindableProperty.ValidateValueDelegate validateValue = null, BindableProperty.BindingPropertyChangedDelegate propertyChanged = null, BindableProperty.BindingPropertyChangingDelegate propertyChanging = null, BindableProperty.CoerceValueDelegate coerceValue = null)
173         {
174             return new BindableProperty (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false);
175         }
176 
177         public static BindableProperty Create<TDeclarer, TPropertyType> (Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay, BindableProperty.ValidateValueDelegate<TPropertyType> validateValue = null, BindableProperty.BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindableProperty.BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, BindableProperty.CoerceValueDelegate<TPropertyType> coerceValue = null) where TDeclarer : BindableObject
178         {
179             return BindableProperty.Create<TDeclarer, TPropertyType> (getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false);
180         }
181 
182         internal static BindableProperty CreateAttached (string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, BindableProperty.ValidateValueDelegate validateValue, BindableProperty.BindingPropertyChangedDelegate propertyChanged, BindableProperty.BindingPropertyChangingDelegate propertyChanging, BindableProperty.CoerceValueDelegate coerceValue, BindableProperty.BindablePropertyBindingChanging bindingChanging, bool isReadOnly)
183         {
184             return new BindableProperty (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging, isReadOnly);
185         }
186 
187         public static BindableProperty CreateAttached (string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay, BindableProperty.ValidateValueDelegate validateValue = null, BindableProperty.BindingPropertyChangedDelegate propertyChanged = null, BindableProperty.BindingPropertyChangingDelegate propertyChanging = null, BindableProperty.CoerceValueDelegate coerceValue = null)
188         {
189             return BindableProperty.CreateAttached (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false);
190         }
191 
192         internal static BindableProperty CreateAttached<TDeclarer, TPropertyType> (Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue, BindingMode defaultBindingMode, BindableProperty.ValidateValueDelegate<TPropertyType> validateValue, BindableProperty.BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindableProperty.BindingPropertyChangingDelegate<TPropertyType> propertyChanging, BindableProperty.CoerceValueDelegate<TPropertyType> coerceValue, BindableProperty.BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false)
193         {
194             if (staticgetter == null) {
195                 throw new ArgumentNullException ("staticgetter");
196             }
197             Expression expression = staticgetter.Body;
198             UnaryExpression unaryExpression = expression as UnaryExpression;
199             if (unaryExpression != null) {
200                 expression = unaryExpression.Operand;
201             }
202             MethodCallExpression methodCallExpression = expression as MethodCallExpression;
203             if (methodCallExpression == null) {
204                 throw new ArgumentException ("staticgetter must be a MethodCallExpression", "staticgetter");
205             }
206             MethodInfo method = methodCallExpression.Method;
207             if (!method.Name.StartsWith ("Get", StringComparison.Ordinal)) {
208                 throw new ArgumentException ("staticgetter name must start with Get", "staticgetter");
209             }
210             string propertyName = method.Name.Substring (3);
211             BindableProperty.ValidateValueDelegate validateValue2 = null;
212             BindableProperty.BindingPropertyChangedDelegate propertyChanged2 = null;
213             BindableProperty.BindingPropertyChangingDelegate propertyChanging2 = null;
214             BindableProperty.CoerceValueDelegate coerceValue2 = null;
215             if (validateValue != null) {
216                 validateValue2 = ((BindableObject bindable, object value) => validateValue (bindable, (TPropertyType)((object)value)));
217             }
218             if (propertyChanged != null) {
219                 propertyChanged2 = delegate (BindableObject bindable, object oldValue, object newValue) {
220                     propertyChanged (bindable, (TPropertyType)((object)oldValue), (TPropertyType)((object)newValue));
221                 };
222             }
223             if (propertyChanging != null) {
224                 propertyChanging2 = delegate (BindableObject bindable, object oldValue, object newValue) {
225                     propertyChanging (bindable, (TPropertyType)((object)oldValue), (TPropertyType)((object)newValue));
226                 };
227             }
228             if (coerceValue != null) {
229                 coerceValue2 = ((BindableObject bindable, object value) => coerceValue (bindable, (TPropertyType)((object)value)));
230             }
231             return new BindableProperty (propertyName, method.ReturnType, typeof(TDeclarer), defaultValue, defaultBindingMode, validateValue2, propertyChanged2, propertyChanging2, coerceValue2, bindingChanging, isReadOnly);
232         }
233 
234         public static BindableProperty CreateAttached<TDeclarer, TPropertyType> (Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay, BindableProperty.ValidateValueDelegate<TPropertyType> validateValue = null, BindableProperty.BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindableProperty.BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, BindableProperty.CoerceValueDelegate<TPropertyType> coerceValue = null)
235         {
236             return BindableProperty.CreateAttached<TDeclarer, TPropertyType> (staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false);
237         }
238 
239         public static BindablePropertyKey CreateAttachedReadOnly<TDeclarer, TPropertyType> (Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource, BindableProperty.ValidateValueDelegate<TPropertyType> validateValue = null, BindableProperty.BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindableProperty.BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, BindableProperty.CoerceValueDelegate<TPropertyType> coerceValue = null)
240         {
241             return new BindablePropertyKey (BindableProperty.CreateAttached<TDeclarer, TPropertyType> (staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true));
242         }
243 
244         public static BindablePropertyKey CreateAttachedReadOnly (string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource, BindableProperty.ValidateValueDelegate validateValue = null, BindableProperty.BindingPropertyChangedDelegate propertyChanged = null, BindableProperty.BindingPropertyChangingDelegate propertyChanging = null, BindableProperty.CoerceValueDelegate coerceValue = null)
245         {
246             return new BindablePropertyKey (BindableProperty.CreateAttached (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true));
247         }
248 
249         public static BindablePropertyKey CreateReadOnly (string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource, BindableProperty.ValidateValueDelegate validateValue = null, BindableProperty.BindingPropertyChangedDelegate propertyChanged = null, BindableProperty.BindingPropertyChangingDelegate propertyChanging = null, BindableProperty.CoerceValueDelegate coerceValue = null)
250         {
251             return new BindablePropertyKey (new BindableProperty (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true));
252         }
253 
254         public static BindablePropertyKey CreateReadOnly<TDeclarer, TPropertyType> (Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource, BindableProperty.ValidateValueDelegate<TPropertyType> validateValue = null, BindableProperty.BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindableProperty.BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, BindableProperty.CoerceValueDelegate<TPropertyType> coerceValue = null) where TDeclarer : BindableObject
255         {
256             return new BindablePropertyKey (BindableProperty.Create<TDeclarer, TPropertyType> (getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true));
257         }
258     }
259 }
View Code

好的,看到BindableObject中的GetValue()方法了吧:

 1 public object GetValue (BindableProperty property)
 2 {
 3     if (property == null) {
 4         throw new ArgumentNullException ("property");
 5     }
 6     object defaultValue;
 7     if (!this.values.TryGetValue (property, out defaultValue)) {
 8         defaultValue = property.DefaultValue;
 9     }
10     return defaultValue;
11 }

7~9行是核心的获取方法,通过查看到非公共部分的代码,可以看到这个values为:

private readonly Dictionary<BindableProperty, object> values;

我们可能关心的是这个方法返回后的Object对象是什么?其实我们可以先把程序跑起来看下具体的返回值:

 

看到是什么东西了吧,是一个NavigationProxy对象,那么我们在找到这个对象看下它的内容吧:

具体代码如下:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Threading.Tasks;
  5 
  6 namespace Xamarin.Forms
  7 {
  8     internal class NavigationProxy : INavigation
  9     {
 10         //
 11         // Fields
 12         //
 13         private INavigation inner;
 14 
 15         private Lazy<Stack<Page>> pushStack = new Lazy<Stack<Page>> (() => new Stack<Page> ());
 16 
 17         private Lazy<Stack<Page>> modalStack = new Lazy<Stack<Page>> (() => new Stack<Page> ());
 18 
 19         //
 20         // Properties
 21         //
 22         public INavigation Inner {
 23             get {
 24                 return this.inner;
 25             }
 26             set {
 27                 if (this.inner == value) {
 28                     return;
 29                 }
 30                 this.inner = value;
 31                 if (object.ReferenceEquals (this.inner, null)) {
 32                     this.pushStack = new Lazy<Stack<Page>> (() => new Stack<Page> ());
 33                     this.modalStack = new Lazy<Stack<Page>> (() => new Stack<Page> ());
 34                     return;
 35                 }
 36                 if (this.pushStack.IsValueCreated) {
 37                     foreach (Page current in this.pushStack.Value.Reverse<Page> ()) {
 38                         this.inner.PushAsync (current);
 39                     }
 40                 }
 41                 if (this.modalStack.IsValueCreated) {
 42                     foreach (Page current2 in this.modalStack.Value.Reverse<Page> ()) {
 43                         this.inner.PushModalAsync (current2);
 44                     }
 45                 }
 46                 this.pushStack = null;
 47                 this.modalStack = null;
 48             }
 49         }
 50 
 51         //
 52         // Methods
 53         //
 54         protected virtual Task<Page> OnPopAsync ()
 55         {
 56             INavigation navigation = this.Inner;
 57             if (navigation != null) {
 58                 return navigation.PopAsync ();
 59             }
 60             return Task.FromResult<Page> (this.pushStack.Value.Pop ());
 61         }
 62 
 63         protected virtual Task<Page> OnPopModal ()
 64         {
 65             INavigation navigation = this.Inner;
 66             if (navigation != null) {
 67                 return navigation.PopModalAsync ();
 68             }
 69             return Task.FromResult<Page> (this.modalStack.Value.Pop ());
 70         }
 71 
 72         protected virtual Task OnPopToRootAsync ()
 73         {
 74             INavigation navigation = this.Inner;
 75             if (navigation == null) {
 76                 Page page = this.pushStack.Value.Last<Page> ();
 77                 this.pushStack.Value.Clear ();
 78                 this.pushStack.Value.Push (page);
 79                 return Task.FromResult<Page> (page);
 80             }
 81             return navigation.PopToRootAsync ();
 82         }
 83 
 84         protected virtual Task OnPushAsync (Page page)
 85         {
 86             INavigation navigation = this.Inner;
 87             if (navigation == null) {
 88                 this.pushStack.Value.Push (page);
 89                 return Task.FromResult<Page> (page);
 90             }
 91             return navigation.PushAsync (page);
 92         }
 93 
 94         protected virtual Task OnPushModal (Page modal)
 95         {
 96             INavigation navigation = this.Inner;
 97             if (navigation == null) {
 98                 this.modalStack.Value.Push (modal);
 99                 return Task.FromResult<object> (null);
100             }
101             return navigation.PushModalAsync (modal);
102         }
103 
104         public Task<Page> PopAsync ()
105         {
106             return this.OnPopAsync ();
107         }
108 
109         public Task<Page> PopModalAsync ()
110         {
111             return this.OnPopModal ();
112         }
113 
114         public Task PopToRootAsync ()
115         {
116             return this.OnPopToRootAsync ();
117         }
118 
119         public Task PushAsync (Page root)
120         {
121             if (root.Parent != null) {
122                 throw new InvalidOperationException ("Page must not already have a parent.");
123             }
124             return this.OnPushAsync (root);
125         }
126 
127         public Task PushModalAsync (Page modal)
128         {
129             if (modal.Parent != null) {
130                 throw new InvalidOperationException ("Page must not already have a parent.");
131             }
132             return this.OnPushModal (modal);
133         }
134     }
135 }
View Code

怎么样,看到里面就是我们要找的东西,那5个方法的具体实现。

可能我们还有一个疑问,那就是在BindableObject中通过 Dictionary<BindableProperty,Object>是如何获取到NavigationProxy的?

在BindableObject中我们查找下所有使用values的地方,发现只有一个地方给这个对象赋值了:方法 SetValueActual

 1 private void SetValueActual (BindableProperty property, object value, bool currentlyApplying, bool clearBindings, bool raiseOnEqual)
 2         {
 3             object defaultValue;
 4             if (!this.values.TryGetValue (property, out defaultValue)) {
 5                 defaultValue = property.DefaultValue;
 6             }
 7             bool flag = object.Equals (value, defaultValue);
 8             if (!flag || raiseOnEqual) {
 9                 if (property.PropertyChanging != null) {
10                     property.PropertyChanging (this, defaultValue, value);
11                 }
12                 this.OnPropertyChanging (property.PropertyName);
13                 this.values [property] = value;
14             }
15             BindingBase bindingBase;
16             if (this.bindings.TryGetValue (property, out bindingBase) && clearBindings && bindingBase.GetRealizedMode (property) == BindingMode.OneWay) {
17                 this.RemoveBinding (property);
18             }
19             if (!flag || raiseOnEqual) {
20                 if (bindingBase != null && !currentlyApplying) {
21                     this.applying = true;
22                     bindingBase.Apply (true);
23                     this.applying = false;
24                 }
25                 this.OnPropertyChanged (property.PropertyName);
26                 if (property.PropertyChanged != null) {
27                     property.PropertyChanged (this, defaultValue, value);
28                 }
29             }
30         }
View Code

这个方法被SetValueCore方法引用:

 1 internal void SetValueCore (BindableProperty property, object value, bool clearBindings, bool raiseOnEqual = false, bool checkaccess = true)
 2         {
 3             if (property == null) {
 4                 throw new ArgumentNullException ("property");
 5             }
 6             if (checkaccess && property.IsReadOnly) {
 7                 return;
 8             }
 9             if (value != null && !property.ReturnType.IsInstanceOfType (value)) {
10                 MethodInfo runtimeMethod = property.ReturnType.GetRuntimeMethod ("op_Implicit", new Type[] {
11                     value.GetType ()
12                 });
13                 if (runtimeMethod == null || runtimeMethod.ReturnType != property.ReturnType) {
14                     Log.Warning ("SetValue", "Can not convert {0} to type '{1}'", new object[] {
15                         value,
16                         property.ReturnType
17                     });
18                     return;
19                 }
20                 value = runtimeMethod.Invoke (null, new object[] {
21                     value
22                 });
23             }
24             if (property.ValidateValue != null && !property.ValidateValue (this, value)) {
25                 throw new ArgumentException ("Value was an invalid value for " + property.PropertyName, "value");
26             }
27             if (property.CoerceValue != null) {
28                 value = property.CoerceValue (this, value);
29             }
30             bool currentlyApplying = this.applying;
31             Queue<Action> queue;
32             if (this.delayedSetters.TryGetValue (property, out queue)) {
33                 queue.Enqueue (delegate {
34                     this.SetValueActual (property, value, currentlyApplying, clearBindings, raiseOnEqual);
35                 });
36                 return;
37             }
38             queue = new Queue<Action> ();
39             this.delayedSetters.Add (property, queue);
40             this.SetValueActual (property, value, currentlyApplying, clearBindings, raiseOnEqual);
41             while (queue.Count > 0) {
42                 Action action = queue.Dequeue ();
43                 action ();
44             }
45             this.delayedSetters.Remove (property);
46         }
View Code

而SetValueCore又被SetValue方法引用:

 1 private void SetValue (BindableProperty property, object value, bool checkaccess)
 2         {
 3             if (property == null) {
 4                 throw new ArgumentNullException ("property");
 5             }
 6             if (checkaccess && property.IsReadOnly) {
 7                 throw new InvalidOperationException (string.Format ("The BindableProperty "{0}" is readonly.", new object[] {
 8                     property.PropertyName
 9                 }));
10             }
11             if (!this.manuallySetValues.Contains (property)) {
12                 this.manuallySetValues.Add (property);
13             }
14             this.SetValueCore (property, value, true, false, checkaccess);
15         }
View Code

但是我们一直没有找到谁在调用SetValue方法,那就往下看看子类中是否调用了,在子类中搜索base.SetValue,结果找到了下面的代码

 1 public INavigation Navigation {
 2             get {
 3                 return (INavigation)base.GetValue  (VisualElement.NavigationProperty);
 4             }
 5             internal set {
 6                 base.SetValue (VisualElement.NavigationPropertyKey, value);
 7             }
 8 }
 9 
10 internal NavigationProxy NavigationProxy {
11   get {
12         return this.Navigation as NavigationProxy;
13     }
14 }
View Code

我们发现了Navigation和NavigationProxy的关系,这个NavigationProxy是由Navigation转过来的。

但是我们如何理解在Navigation属性的set访问器中是如何将 NavigationProxy对象赋值的?这个还需要再详细的梳理下。

下面我们看下这个Navigation.PushAsync()是如何实现页面跳转的。

原文地址:https://www.cnblogs.com/lvfeilong/p/4654gfhg.html