Xamarin.Forms中 Navigation,NavigationPage详解

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:

Xamarin.Forms中 Navigation,NavigationPage详解

ContentPage:

Xamarin.Forms中 Navigation,NavigationPage详解

TabbedPage:

Xamarin.Forms中 Navigation,NavigationPage详解

CarouselPage:

Xamarin.Forms中 Navigation,NavigationPage详解

MasterDetailPage:

Xamarin.Forms中 Navigation,NavigationPage详解

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对象是什么?其实我们可以先把程序跑起来看下具体的返回值:

Xamarin.Forms中 Navigation,NavigationPage详解 

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

Xamarin.Forms中 Navigation,NavigationPage详解

具体代码如下:

 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()是如何实现页面跳转的。

上一篇:PHP全栈学习笔记16


下一篇:Xamarin XAML语言教程Xamarin.Forms中活动指示器的显示隐藏