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的具体内容:


这个对象中有一个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如下

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.CompilerServices; namespace Xamarin.Forms
{
public abstract class BindableObject : INotifyPropertyChanged
{
//
// Static Fields
//
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)); //
// Properties
//
public object BindingContext {
get {
return this.inheritedContext ?? this.GetValue (BindableObject.BindingContextProperty);
}
set {
this.SetValue (BindableObject.BindingContextProperty, value);
}
} //
// Constructors
//
protected BindableObject ()
{
this.bindings = new Dictionary<BindableProperty, BindingBase> ();
this.values = new Dictionary<BindableProperty, object> ();
this.manuallySetValues = new List<BindableProperty> ();
this.delayedSetters = new Dictionary<BindableProperty, Queue<Action>> ();
base..ctor ();
} //
// Static Methods
//
private static void BindingContextPropertyBindingChanging (BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
{
object context = bindable.inheritedContext;
Binding binding = oldBindingBase as Binding;
Binding binding2 = newBindingBase as Binding;
if (context == null && binding != null) {
context = binding.Context;
}
if (context != null && binding2 != null) {
binding2.Context = context;
}
} private static void BindingContextPropertyBindingPropertyChanged (BindableObject bindable, object oldvalue, object newvalue)
{
object obj = bindable.inheritedContext;
bindable.inheritedContext = null;
bindable.ApplyBindings (obj ?? oldvalue);
bindable.OnBindingContextChanged ();
} protected static void SetInheritedBindingContext (BindableObject bindable, object value)
{
if (bindable.HasManuallySetValue (BindableObject.BindingContextProperty)) {
return;
}
object bindingContext = bindable.BindingContext;
BindingBase bindingBase;
if (bindable.bindings.TryGetValue (BindableObject.BindingContextProperty, out bindingBase)) {
((Binding)bindingBase).Context = value;
bindable.inheritedContext = null;
}
else {
if (object.ReferenceEquals (bindable.BindingContext, value)) {
return;
}
bindable.inheritedContext = value;
}
bindable.ApplyBindings (bindingContext);
bindable.OnBindingContextChanged ();
} //
// Methods
//
protected void ApplyBindings (object oldContext = null)
{
foreach (KeyValuePair<BindableProperty, BindingBase> current in this.bindings) {
if (oldContext != null) {
current.Value.Unapply ();
}
current.Value.Apply (this.BindingContext, this, current.Key);
}
} public void ClearValue (BindableProperty property)
{
this.ClearValue (property, true);
} public void ClearValue (BindablePropertyKey propertyKey)
{
if (propertyKey == null) {
throw new ArgumentNullException ("propertyKey");
}
this.ClearValue (propertyKey.BindableProperty, false);
} private void ClearValue (BindableProperty property, bool checkaccess)
{
if (property == null) {
throw new ArgumentNullException ("property");
}
if (checkaccess && property.IsReadOnly) {
throw new InvalidOperationException (string.Format ("The BindableProperty "{}" is readonly.", new object[] {
property.PropertyName
}));
}
object value = this.GetValue (property);
object defaultValue = property.DefaultValue;
bool flag = object.Equals (value, defaultValue);
if (!flag) {
if (property.PropertyChanging != null) {
property.PropertyChanging (this, value, property.DefaultValue);
}
this.OnPropertyChanging (property.PropertyName);
}
this.manuallySetValues.Remove (property);
this.values.Remove (property);
if (!flag) {
this.OnPropertyChanged (property.PropertyName);
if (property.PropertyChanged != null) {
property.PropertyChanged (this, value, property.DefaultValue);
}
}
} internal bool GetIsBound (BindableProperty targetProperty)
{
if (targetProperty == null) {
throw new ArgumentNullException ("targetProperty");
}
return this.bindings.ContainsKey (targetProperty);
} public object GetValue (BindableProperty property)
{
if (property == null) {
throw new ArgumentNullException ("property");
}
object defaultValue;
if (!this.values.TryGetValue (property, out defaultValue)) {
defaultValue = property.DefaultValue;
}
return defaultValue;
} private bool HasManuallySetValue (BindableProperty property)
{
if (property == null) {
throw new ArgumentNullException ("property");
}
return this.manuallySetValues.Contains (property);
} protected virtual void OnBindingContextChanged ()
{
EventHandler bindingContextChanged = this.BindingContextChanged;
if (bindingContextChanged != null) {
bindingContextChanged (this, EventArgs.Empty);
}
} protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if (propertyChanged != null) {
propertyChanged (this, new PropertyChangedEventArgs (propertyName));
}
} protected virtual void OnPropertyChanging ([CallerMemberName] string propertyName = null)
{
PropertyChangingEventHandler propertyChanging = this.PropertyChanging;
if (propertyChanging != null) {
propertyChanging (this, new PropertyChangingEventArgs (propertyName));
}
} public void RemoveBinding (BindableProperty property)
{
if (property == null) {
throw new ArgumentNullException ("property");
}
BindingBase bindingBase;
if (!this.bindings.TryGetValue (property, out bindingBase)) {
return;
}
bindingBase.Unapply ();
if (property.BindingChanging != null) {
property.BindingChanging (this, bindingBase, null);
}
this.bindings.Remove (property);
} public void SetBinding (BindableProperty targetProperty, BindingBase binding)
{
if (targetProperty == null) {
throw new ArgumentNullException ("targetProperty");
}
if (binding == null) {
throw new ArgumentNullException ("binding");
}
BindingBase bindingBase;
if (this.bindings.TryGetValue (targetProperty, out bindingBase)) {
bindingBase.Unapply ();
}
this.bindings [targetProperty] = binding;
if (targetProperty.BindingChanging != null) {
targetProperty.BindingChanging (this, bindingBase, binding);
}
binding.Apply (this.BindingContext, this, targetProperty);
} private void SetValue (BindableProperty property, object value, bool checkaccess)
{
if (property == null) {
throw new ArgumentNullException ("property");
}
if (checkaccess && property.IsReadOnly) {
throw new InvalidOperationException (string.Format ("The BindableProperty "{}" is readonly.", new object[] {
property.PropertyName
}));
}
if (!this.manuallySetValues.Contains (property)) {
this.manuallySetValues.Add (property);
}
this.SetValueCore (property, value, true, false, checkaccess);
} public void SetValue (BindablePropertyKey propertyKey, object value)
{
if (propertyKey == null) {
throw new ArgumentNullException ("propertyKey");
}
this.SetValue (propertyKey.BindableProperty, value, false);
} public void SetValue (BindableProperty property, object value)
{
this.SetValue (property, value, true);
} private void SetValueActual (BindableProperty property, object value, bool currentlyApplying, bool clearBindings, bool raiseOnEqual)
{
object defaultValue;
if (!this.values.TryGetValue (property, out defaultValue)) {
defaultValue = property.DefaultValue;
}
bool flag = object.Equals (value, defaultValue);
if (!flag || raiseOnEqual) {
if (property.PropertyChanging != null) {
property.PropertyChanging (this, defaultValue, value);
}
this.OnPropertyChanging (property.PropertyName);
this.values [property] = value;
}
BindingBase bindingBase;
if (this.bindings.TryGetValue (property, out bindingBase) && clearBindings && bindingBase.GetRealizedMode (property) == BindingMode.OneWay) {
this.RemoveBinding (property);
}
if (!flag || raiseOnEqual) {
if (bindingBase != null && !currentlyApplying) {
this.applying = true;
bindingBase.Apply (true);
this.applying = false;
}
this.OnPropertyChanged (property.PropertyName);
if (property.PropertyChanged != null) {
property.PropertyChanged (this, defaultValue, value);
}
}
} internal void SetValueCore (BindableProperty property, object value, bool clearBindings, bool raiseOnEqual = false, bool checkaccess = true)
{
if (property == null) {
throw new ArgumentNullException ("property");
}
if (checkaccess && property.IsReadOnly) {
return;
}
if (value != null && !property.ReturnType.IsInstanceOfType (value)) {
MethodInfo runtimeMethod = property.ReturnType.GetRuntimeMethod ("op_Implicit", new Type[] {
value.GetType ()
});
if (runtimeMethod == null || runtimeMethod.ReturnType != property.ReturnType) {
Log.Warning ("SetValue", "Can not convert {0} to type '{1}'", new object[] {
value,
property.ReturnType
});
return;
}
value = runtimeMethod.Invoke (null, new object[] {
value
});
}
if (property.ValidateValue != null && !property.ValidateValue (this, value)) {
throw new ArgumentException ("Value was an invalid value for " + property.PropertyName, "value");
}
if (property.CoerceValue != null) {
value = property.CoerceValue (this, value);
}
bool currentlyApplying = this.applying;
Queue<Action> queue;
if (this.delayedSetters.TryGetValue (property, out queue)) {
queue.Enqueue (delegate {
this.SetValueActual (property, value, currentlyApplying, clearBindings, raiseOnEqual);
});
return;
}
queue = new Queue<Action> ();
this.delayedSetters.Add (property, queue);
this.SetValueActual (property, value, currentlyApplying, clearBindings, raiseOnEqual);
while (queue.Count > ) {
Action action = queue.Dequeue ();
action ();
}
this.delayedSetters.Remove (property);
} protected void UnapplyBindings ()
{
foreach (BindingBase current in this.bindings.Values) {
current.Unapply ();
}
} //
// Events
//
public event PropertyChangingEventHandler PropertyChanging; public event PropertyChangedEventHandler PropertyChanged; public event EventHandler BindingContextChanged;
}
}

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

 using System;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection; namespace Xamarin.Forms
{
[DebuggerDisplay ("{PropertyName}")]
public sealed class BindableProperty
{
internal delegate void BindablePropertyBindingChanging (BindableObject bindable, BindingBase oldValue, BindingBase newValue); public delegate void BindingPropertyChangedDelegate (BindableObject bindable, object oldValue, object newValue); public delegate void BindingPropertyChangedDelegate<TPropertyType> (BindableObject bindable, TPropertyType oldValue, TPropertyType newValue); public delegate void BindingPropertyChangingDelegate<TPropertyType> (BindableObject bindable, TPropertyType oldValue, TPropertyType newValue); public delegate void BindingPropertyChangingDelegate (BindableObject bindable, object oldValue, object newValue); public delegate object CoerceValueDelegate (BindableObject bindable, object value); public delegate TPropertyType CoerceValueDelegate<TPropertyType> (BindableObject bindable, TPropertyType value); public delegate bool ValidateValueDelegate (BindableObject bindable, object value); public delegate bool ValidateValueDelegate<TPropertyType> (BindableObject bindable, TPropertyType value); //
// Properties
//
internal BindableProperty.BindablePropertyBindingChanging BindingChanging {
get;
private set;
} internal BindableProperty.CoerceValueDelegate CoerceValue {
get;
private set;
} public Type DeclaringType {
get;
private set;
} public BindingMode DefaultBindingMode {
get;
private set;
} public object DefaultValue {
get;
private set;
} public bool IsReadOnly {
get;
private set;
} internal BindableProperty.BindingPropertyChangedDelegate PropertyChanged {
get;
private set;
} internal BindableProperty.BindingPropertyChangingDelegate PropertyChanging {
get;
private set;
} public string PropertyName {
get;
private set;
} public Type ReturnType {
get;
private set;
} internal BindableProperty.ValidateValueDelegate ValidateValue {
get;
private set;
} //
// Constructors
//
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)
{
if (propertyName == null) {
throw new ArgumentNullException ("propertyName");
}
if (object.ReferenceEquals (returnType, null)) {
throw new ArgumentNullException ("returnType");
}
if (object.ReferenceEquals (declaringType, null)) {
throw new ArgumentNullException ("declaringType");
}
if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay) {
throw new ArgumentException ("Not a valid type of BindingMode", "defaultBindingMode");
}
if (defaultValue == null && Nullable.GetUnderlyingType (returnType) == null && returnType.GetTypeInfo ().IsValueType) {
throw new ArgumentException ("Not a valid default value", "defaultValue");
}
if (defaultValue != null && !returnType.IsInstanceOfType (defaultValue)) {
throw new ArgumentException ("Default value did not match return type", "defaultValue");
}
if (defaultBindingMode == BindingMode.Default) {
defaultBindingMode = BindingMode.OneWay;
}
this.PropertyName = propertyName;
this.ReturnType = returnType;
this.DeclaringType = declaringType;
this.DefaultValue = defaultValue;
this.DefaultBindingMode = defaultBindingMode;
this.PropertyChanged = propertyChanged;
this.PropertyChanging = propertyChanging;
this.ValidateValue = validateValue;
this.CoerceValue = coerceValue;
this.BindingChanging = bindingChanging;
this.IsReadOnly = isReadOnly;
} //
// Static Methods
//
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)
{
return new BindableProperty (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging, false);
} 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
{
if (getter == null) {
throw new ArgumentNullException ("getter");
}
Expression expression = getter.Body;
UnaryExpression unaryExpression = expression as UnaryExpression;
if (unaryExpression != null) {
expression = unaryExpression.Operand;
}
MemberExpression memberExpression = expression as MemberExpression;
if (memberExpression == null) {
throw new ArgumentException ("getter must be a MemberExpression", "getter");
}
PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member;
BindableProperty.ValidateValueDelegate validateValue2 = null;
BindableProperty.BindingPropertyChangedDelegate propertyChanged2 = null;
BindableProperty.BindingPropertyChangingDelegate propertyChanging2 = null;
BindableProperty.CoerceValueDelegate coerceValue2 = null;
if (validateValue != null) {
validateValue2 = ((BindableObject bindable, object value) => validateValue (bindable, (TPropertyType)((object)value)));
}
if (propertyChanged != null) {
propertyChanged2 = delegate (BindableObject bindable, object oldValue, object newValue) {
propertyChanged (bindable, (TPropertyType)((object)oldValue), (TPropertyType)((object)newValue));
};
}
if (propertyChanging != null) {
propertyChanging2 = delegate (BindableObject bindable, object oldValue, object newValue) {
propertyChanging (bindable, (TPropertyType)((object)oldValue), (TPropertyType)((object)newValue));
};
}
if (coerceValue != null) {
coerceValue2 = ((BindableObject bindable, object value) => coerceValue (bindable, (TPropertyType)((object)value)));
}
return new BindableProperty (propertyInfo.Name, propertyInfo.PropertyType, typeof(TDeclarer), defaultValue, defaultBindingMode, validateValue2, propertyChanged2, propertyChanging2, coerceValue2, bindingChanging, isReadOnly);
} 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)
{
return new BindableProperty (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false);
} 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
{
return BindableProperty.Create<TDeclarer, TPropertyType> (getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false);
} 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)
{
return new BindableProperty (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging, isReadOnly);
} 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)
{
return BindableProperty.CreateAttached (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false);
} 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)
{
if (staticgetter == null) {
throw new ArgumentNullException ("staticgetter");
}
Expression expression = staticgetter.Body;
UnaryExpression unaryExpression = expression as UnaryExpression;
if (unaryExpression != null) {
expression = unaryExpression.Operand;
}
MethodCallExpression methodCallExpression = expression as MethodCallExpression;
if (methodCallExpression == null) {
throw new ArgumentException ("staticgetter must be a MethodCallExpression", "staticgetter");
}
MethodInfo method = methodCallExpression.Method;
if (!method.Name.StartsWith ("Get", StringComparison.Ordinal)) {
throw new ArgumentException ("staticgetter name must start with Get", "staticgetter");
}
string propertyName = method.Name.Substring ();
BindableProperty.ValidateValueDelegate validateValue2 = null;
BindableProperty.BindingPropertyChangedDelegate propertyChanged2 = null;
BindableProperty.BindingPropertyChangingDelegate propertyChanging2 = null;
BindableProperty.CoerceValueDelegate coerceValue2 = null;
if (validateValue != null) {
validateValue2 = ((BindableObject bindable, object value) => validateValue (bindable, (TPropertyType)((object)value)));
}
if (propertyChanged != null) {
propertyChanged2 = delegate (BindableObject bindable, object oldValue, object newValue) {
propertyChanged (bindable, (TPropertyType)((object)oldValue), (TPropertyType)((object)newValue));
};
}
if (propertyChanging != null) {
propertyChanging2 = delegate (BindableObject bindable, object oldValue, object newValue) {
propertyChanging (bindable, (TPropertyType)((object)oldValue), (TPropertyType)((object)newValue));
};
}
if (coerceValue != null) {
coerceValue2 = ((BindableObject bindable, object value) => coerceValue (bindable, (TPropertyType)((object)value)));
}
return new BindableProperty (propertyName, method.ReturnType, typeof(TDeclarer), defaultValue, defaultBindingMode, validateValue2, propertyChanged2, propertyChanging2, coerceValue2, bindingChanging, isReadOnly);
} 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)
{
return BindableProperty.CreateAttached<TDeclarer, TPropertyType> (staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false);
} 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)
{
return new BindablePropertyKey (BindableProperty.CreateAttached<TDeclarer, TPropertyType> (staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true));
} 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)
{
return new BindablePropertyKey (BindableProperty.CreateAttached (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true));
} 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)
{
return new BindablePropertyKey (new BindableProperty (propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true));
} 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
{
return new BindablePropertyKey (BindableProperty.Create<TDeclarer, TPropertyType> (getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true));
}
}
}

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

 public object GetValue (BindableProperty property)
{
if (property == null) {
throw new ArgumentNullException ("property");
}
object defaultValue;
if (!this.values.TryGetValue (property, out defaultValue)) {
defaultValue = property.DefaultValue;
}
return defaultValue;
}

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

private readonly Dictionary<BindableProperty, object> values;

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

 

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

具体代码如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; namespace Xamarin.Forms
{
internal class NavigationProxy : INavigation
{
//
// Fields
//
private INavigation inner; private Lazy<Stack<Page>> pushStack = new Lazy<Stack<Page>> (() => new Stack<Page> ()); private Lazy<Stack<Page>> modalStack = new Lazy<Stack<Page>> (() => new Stack<Page> ()); //
// Properties
//
public INavigation Inner {
get {
return this.inner;
}
set {
if (this.inner == value) {
return;
}
this.inner = value;
if (object.ReferenceEquals (this.inner, null)) {
this.pushStack = new Lazy<Stack<Page>> (() => new Stack<Page> ());
this.modalStack = new Lazy<Stack<Page>> (() => new Stack<Page> ());
return;
}
if (this.pushStack.IsValueCreated) {
foreach (Page current in this.pushStack.Value.Reverse<Page> ()) {
this.inner.PushAsync (current);
}
}
if (this.modalStack.IsValueCreated) {
foreach (Page current2 in this.modalStack.Value.Reverse<Page> ()) {
this.inner.PushModalAsync (current2);
}
}
this.pushStack = null;
this.modalStack = null;
}
} //
// Methods
//
protected virtual Task<Page> OnPopAsync ()
{
INavigation navigation = this.Inner;
if (navigation != null) {
return navigation.PopAsync ();
}
return Task.FromResult<Page> (this.pushStack.Value.Pop ());
} protected virtual Task<Page> OnPopModal ()
{
INavigation navigation = this.Inner;
if (navigation != null) {
return navigation.PopModalAsync ();
}
return Task.FromResult<Page> (this.modalStack.Value.Pop ());
} protected virtual Task OnPopToRootAsync ()
{
INavigation navigation = this.Inner;
if (navigation == null) {
Page page = this.pushStack.Value.Last<Page> ();
this.pushStack.Value.Clear ();
this.pushStack.Value.Push (page);
return Task.FromResult<Page> (page);
}
return navigation.PopToRootAsync ();
} protected virtual Task OnPushAsync (Page page)
{
INavigation navigation = this.Inner;
if (navigation == null) {
this.pushStack.Value.Push (page);
return Task.FromResult<Page> (page);
}
return navigation.PushAsync (page);
} protected virtual Task OnPushModal (Page modal)
{
INavigation navigation = this.Inner;
if (navigation == null) {
this.modalStack.Value.Push (modal);
return Task.FromResult<object> (null);
}
return navigation.PushModalAsync (modal);
} public Task<Page> PopAsync ()
{
return this.OnPopAsync ();
} public Task<Page> PopModalAsync ()
{
return this.OnPopModal ();
} public Task PopToRootAsync ()
{
return this.OnPopToRootAsync ();
} public Task PushAsync (Page root)
{
if (root.Parent != null) {
throw new InvalidOperationException ("Page must not already have a parent.");
}
return this.OnPushAsync (root);
} public Task PushModalAsync (Page modal)
{
if (modal.Parent != null) {
throw new InvalidOperationException ("Page must not already have a parent.");
}
return this.OnPushModal (modal);
}
}
}

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

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

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

 private void SetValueActual (BindableProperty property, object value, bool currentlyApplying, bool clearBindings, bool raiseOnEqual)
{
object defaultValue;
if (!this.values.TryGetValue (property, out defaultValue)) {
defaultValue = property.DefaultValue;
}
bool flag = object.Equals (value, defaultValue);
if (!flag || raiseOnEqual) {
if (property.PropertyChanging != null) {
property.PropertyChanging (this, defaultValue, value);
}
this.OnPropertyChanging (property.PropertyName);
this.values [property] = value;
}
BindingBase bindingBase;
if (this.bindings.TryGetValue (property, out bindingBase) && clearBindings && bindingBase.GetRealizedMode (property) == BindingMode.OneWay) {
this.RemoveBinding (property);
}
if (!flag || raiseOnEqual) {
if (bindingBase != null && !currentlyApplying) {
this.applying = true;
bindingBase.Apply (true);
this.applying = false;
}
this.OnPropertyChanged (property.PropertyName);
if (property.PropertyChanged != null) {
property.PropertyChanged (this, defaultValue, value);
}
}
}

这个方法被SetValueCore方法引用:

 internal void SetValueCore (BindableProperty property, object value, bool clearBindings, bool raiseOnEqual = false, bool checkaccess = true)
{
if (property == null) {
throw new ArgumentNullException ("property");
}
if (checkaccess && property.IsReadOnly) {
return;
}
if (value != null && !property.ReturnType.IsInstanceOfType (value)) {
MethodInfo runtimeMethod = property.ReturnType.GetRuntimeMethod ("op_Implicit", new Type[] {
value.GetType ()
});
if (runtimeMethod == null || runtimeMethod.ReturnType != property.ReturnType) {
Log.Warning ("SetValue", "Can not convert {0} to type '{1}'", new object[] {
value,
property.ReturnType
});
return;
}
value = runtimeMethod.Invoke (null, new object[] {
value
});
}
if (property.ValidateValue != null && !property.ValidateValue (this, value)) {
throw new ArgumentException ("Value was an invalid value for " + property.PropertyName, "value");
}
if (property.CoerceValue != null) {
value = property.CoerceValue (this, value);
}
bool currentlyApplying = this.applying;
Queue<Action> queue;
if (this.delayedSetters.TryGetValue (property, out queue)) {
queue.Enqueue (delegate {
this.SetValueActual (property, value, currentlyApplying, clearBindings, raiseOnEqual);
});
return;
}
queue = new Queue<Action> ();
this.delayedSetters.Add (property, queue);
this.SetValueActual (property, value, currentlyApplying, clearBindings, raiseOnEqual);
while (queue.Count > ) {
Action action = queue.Dequeue ();
action ();
}
this.delayedSetters.Remove (property);
}

而SetValueCore又被SetValue方法引用:

 private void SetValue (BindableProperty property, object value, bool checkaccess)
{
if (property == null) {
throw new ArgumentNullException ("property");
}
if (checkaccess && property.IsReadOnly) {
throw new InvalidOperationException (string.Format ("The BindableProperty "{}" is readonly.", new object[] {
property.PropertyName
}));
}
if (!this.manuallySetValues.Contains (property)) {
this.manuallySetValues.Add (property);
}
this.SetValueCore (property, value, true, false, checkaccess);
}

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

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

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

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

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

Xamarin.Forms中 Navigation,NavigationPage详解的更多相关文章

  1. Xamarin android CardView的使用详解

    android 5.0新增加的一个控件CardView,在support v7兼容包中,意思就是卡片View,虽然可以设置阴影,圆角等等样式,但是我们也可以自己写出来,谷歌工程师之所以出这个,肯定是帮 ...

  2. php中关于引用(&)详解

    php中关于引用(&)详解 php的引用(就是在变量或者函数.对象等前面加上&符号) 在PHP 中引用的意思是:不同的变量名访问同一个变量内容. 与C语言中的指针是有差别的.C语言中的 ...

  3. JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解

    二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...

  4. AngularJS select中ngOptions用法详解

    AngularJS select中ngOptions用法详解   一.用法 ngOption针对不同类型的数据源有不同的用法,主要体现在数组和对象上. 数组: label for value in a ...

  5. 【转载】C/C++中extern关键字详解

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...

  6. oracle中imp命令详解 .

    转自http://www.cnblogs.com/songdavid/articles/2435439.html oracle中imp命令详解 Oracle的导入实用程序(Import utility ...

  7. Android中Service(服务)详解

    http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...

  8. python中threading模块详解(一)

    python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...

  9. Xamarin.Forms中的ListView的ItemTrapped事件与ItemSelected事件的区别

    今天对Xamarin.Forms中的ListView的两个事件(ItemTrapped和ItemSelected)做了小小的研究,发现有以下几点区别: 1.ItemTrapped事件会优先被触发. 2 ...

随机推荐

  1. 在Android Studio 0.5.2中使用ArcGIS Android SDK

    环境 操作系统:Mac OSX 10.8.5Android Studio: 0.5.2ArcGIS Android SDK: 10.2.3 操作步骤 在Android Studio中新建一个Modul ...

  2. Bilateral Filtering(双边滤波) for SSAO

    原网址:http://blog.csdn.net/bugrunner/article/details/7170471 1. 简介 图像平滑是一个重要的操作,而且有多种成熟的算法.这里主要简单介绍一下B ...

  3. Windows Ruby 安装步骤

    by 狂奔的蜗牛的博客 from http://www.host900.com/ 本文地址:http://www.host900.com/index.php/articles/285/ Windows ...

  4. CentOS6上安装Flash Player

    Linux CentOS6服务器中的某个需要远程操作的项目需要使用到Adobe Flash Player组件,直接通过YUM方式安装不了,于是通过强大的搜索,还是可以解决到安装方法的,通过重新加载安装 ...

  5. CBCentralManagerDelegate Protocol 委托协议相关分析

    总体概述 CBCentralManagerDelegate 协议中定义了一系列方法列表,这些方法是委托对象必须要实现的方法(也有可选择的),当中央管理器的相应变化就会调用委托对象中实现的相应方法. M ...

  6. 117 FP页面无法查看 此错误是JDK8.0.0.0版本的一个BUG,会导致工单重复回写,

    用户表示117 FP页面无法查看,提示如下错误: 跟进: 1.进入FP服务器可看到以下错误 这个错误的框就表示FP的一个进程报错,自动断掉了,需要重新跑一次EXIT,INIT,PLAN,EXPORT, ...

  7. git远程代码库回滚(webstorm下)

    git远程代码库回滚(webstorm下) 1. 场景 添加了一个文件[file-for-test.js]到git的控制下 进行了三次修改,并分别进行了三次commit,最后进行了一次push git ...

  8. Struts2项目走向流转

    ----------------siwuxie095 Struts2 项目走向流转 1.HTTP 请求流转过程 2.配置文件连接点详解 [made by siwuxie095]

  9. SpringMVC单元测试-MockMvc

    一 简介 MockMvc实现对Http请求的模拟,可以方便对Controller进行测试,使得测试速度快.不依赖网络环境,而且提供验证的工具,使得请求的验证统一而且很方便.   二 常见使用方式 1  ...

  10. 为什么要使用href=”javascript:void(0);”

    为什么要使用href=”javascript:void(0);”   href=”javascript:void(0);”这个的含义是,让超链接去执行一个js函数,而不是去跳转到一个地址,而void( ...