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如下
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 }