日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

解读WPF中的Xaml

發布時間:2023/12/4 asp.net 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 解读WPF中的Xaml 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.Overview

這篇文章主要分享從源代碼角度解讀wpf中xaml。由于源碼查看起來錯綜復雜“隨便找一個對象按下F12就是一個新的世界”,看源碼的感覺就是在盜夢空間里來回穿梭;所以也是耗費很長的時間去閱讀源碼然后根據自己的理解編寫文章和貼出部分關鍵源碼。

2.Detail

大概將從編譯、讀取、加載這幾個維度來解讀。以防后面看源碼會暈,先直接講結果;

  • 編寫(可通過vs完成)

  • 編譯(可通過vs完成)

  • 讀取、加載

有的帥氣的觀眾就會問了,這些研究在實際在項目中應用場景是什么?

? ? ? ? ?選擇性的加載xaml(baml)文件來達到更改UI的操作。

  • 動態換膚,大家都用過手機app每到過年過節都會看到界面上會出現對應的主題,那么我們就可以在程序內設定到了某個節日直接加載對應主題界面的xaml(baml)文件來達到這種效果,對于動態皮膚場景來說,在運行時加載和解析XAML是有意義的。

  • 加載不同的.xaml(.baml)文件,以適應不同分辨率的布局

  • 簡單固定的UI美工人員將設計稿轉換為位圖,可使用blend或者 expression design轉成對應的wpf界面

還可以適配不同的業務要求。可能這種延伸就是研究的意義吧

(1)編譯xaml

XAML不僅要能夠解決涉及協作問題,它還需要快速運行。盡管基于XML格式可以很靈活并且很容易地遷移到其他平臺和工具,但未必是有效的選擇。XML的涉及目標是具有邏輯性、易讀而且簡單,沒有被壓縮。WPF 使用 BAML(Binaiy Application Markup Language,二進制應用程序標記語言)來克服這 個缺點。BAML 并非新事物,它實際上就是 XAML 的二進制表示,當在 Visual Studio 中編譯 WPF 應用程序時,所有 XAML 文件都被轉換為 BAML這些 BAML 然后作為資源被嵌入到最 終的 DLL 或 EXE 程序集中。BAML 是標記化的,這意味著較長的 XAML 被較短的標記替代。BAML 不僅明顯小一些,還對其進行了優化,從而使它在運行時能夠更快地解析。并成為一個內嵌資源;

BAML由VS編譯生成存在,obj目錄的debug下;

通過IL反編譯項目文件之后,可以看到編譯完成之后將會被連接到工程的“資源清單”當中。

使用Assembly的GetManifestResourceStream方法,可以在運行期獲取到這個二進制流

Assembly asm = Assembly.GetExecutingAssembly( ); Stream s = asm.GetManifestResourceStream("StreamName");

(2)讀取、加載xaml(baml)

使用代碼和未經編譯的標記(XAML),這種具體方式對于某些特殊情況是很苻意義的* 例如創建高度動態化的用戶界面。這種方式在運行時使用 System.Windows.Markup 名 稱空間中的 從 XAML 文件中加載部分用戶界面。使用代碼和編譯過的標記(BAML),對于 WPF 而言這是一種更好的方式,也是 Visual Studio 支持的一種方式。這種方式為每個窗口創建一個 XAML 橫板,這個 XAML 模板 被編譯為 BAML,并嵌入到最終的程序集中。編譯過的 BAML 在運行時被提取出來, 用于重新生成用戶界面。

  • 1.當客戶端程序被啟動時Runtime接管代碼來創建window實例

internal object CreateInstanceImpl(BindingFlags bindingAttr,Binder binder,object[] args,CultureInfo culture,object[] activationAttributes,ref StackCrawlMark stackMark){this.CreateInstanceCheckThis();object obj = (object) null;try{try{if (activationAttributes != null)ActivationServices.PushActivationAttributes((Type) this, activationAttributes);if (args == null)args = EmptyArray<object>.Value;int length = args.Length;if (binder == null)binder = Type.DefaultBinder;if (length == 0 && (bindingAttr & BindingFlags.Public) != BindingFlags.Default && (bindingAttr & BindingFlags.Instance) != BindingFlags.Default && (this.IsGenericCOMObjectImpl() || this.IsValueType)){obj = this.CreateInstanceDefaultCtor((bindingAttr & BindingFlags.NonPublic) == BindingFlags.Default, false, true, ref stackMark);}else{ConstructorInfo[] constructors = this.GetConstructors(bindingAttr);List<MethodBase> methodBaseList = new List<MethodBase>(constructors.Length);Type[] argumentTypes = new Type[length];for (int index = 0; index < length; ++index){if (args[index] != null)argumentTypes[index] = args[index].GetType();}for (int index = 0; index < constructors.Length; ++index){if (RuntimeType.FilterApplyConstructorInfo((RuntimeConstructorInfo) constructors[index], bindingAttr, CallingConventions.Any, argumentTypes))methodBaseList.Add((MethodBase) constructors[index]);}MethodBase[] methodBaseArray = new MethodBase[methodBaseList.Count];methodBaseList.CopyTo(methodBaseArray);if (methodBaseArray != null && methodBaseArray.Length == 0)methodBaseArray = (MethodBase[]) null;if (methodBaseArray == null){if (activationAttributes != null){ActivationServices.PopActivationAttributes((Type) this);activationAttributes = (object[]) null;}throw new MissingMethodException(Environment.GetResourceString("MissingConstructor_Name", (object) this.FullName));}object state = (object) null;MethodBase methodBase;try{methodBase = binder.BindToMethod(bindingAttr, methodBaseArray, ref args, (ParameterModifier[]) null, culture, (string[]) null, out state);}catch (MissingMethodException ex){methodBase = (MethodBase) null;}if (methodBase == (MethodBase) null){if (activationAttributes != null){ActivationServices.PopActivationAttributes((Type) this);activationAttributes = (object[]) null;}throw new MissingMethodException(Environment.GetResourceString("MissingConstructor_Name", (object) this.FullName));}if (RuntimeType.DelegateType.IsAssignableFrom(methodBase.DeclaringType))new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();if (methodBase.GetParametersNoCopy().Length == 0){if (args.Length != 0)throw new NotSupportedException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, Environment.GetResourceString("NotSupported_CallToVarArg")));obj = Activator.CreateInstance((Type) this, true);}else{obj = ((ConstructorInfo) methodBase).Invoke(bindingAttr, binder, args, culture);if (state != null)binder.ReorderArgumentArray(ref args, state);}}}finally{if (activationAttributes != null){ActivationServices.PopActivationAttributes((Type) this);activationAttributes = (object[]) null;}}}catch (Exception ex){throw;}return obj;}
  • 2.Window構造函數調用Application.LoadComponent讀取創建.xaml(baml)

IL反編譯后的代碼

/// <summary> /// MainWindow /// </summary> public partial class MainWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector {#line 10 "..\..\..\MainWindow.xaml"[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]internal System.Windows.Controls.TextBox textBox;#line default#line hiddenprivate bool _contentLoaded;/// <summary>/// InitializeComponent/// </summary>[System.Diagnostics.DebuggerNonUserCodeAttribute()][System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "6.0.0.0")]public void InitializeComponent() {if (_contentLoaded) {return;}_contentLoaded = true;System.Uri resourceLocater = new System.Uri("/WpfApp1;component/mainwindow.xaml", System.UriKind.Relative);#line 1 "..\..\..\MainWindow.xaml"System.Windows.Application.LoadComponent(this, resourceLocater);#line default#line hidden}[System.Diagnostics.DebuggerNonUserCodeAttribute()][System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "6.0.0.0")][System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)][System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")][System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")][System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) {switch (connectionId){case 1:this.textBox = ((System.Windows.Controls.TextBox)(target));return;}this._contentLoaded = true;} }
  • 3.Application.LoadComponent()加載baml

public static void LoadComponent(object component, Uri resourceLocator) {if (component == null)throw new ArgumentNullException(nameof (component));if (resourceLocator == (Uri) null)throw new ArgumentNullException(nameof (resourceLocator));if (resourceLocator.OriginalString == null)throw new ArgumentException(SR.Get("ArgumentPropertyMustNotBeNull", (object) nameof (resourceLocator), (object) "OriginalString"));Uri curComponentUri = !resourceLocator.IsAbsoluteUri ? new Uri(BaseUriHelper.PackAppBaseUri, resourceLocator) : throw new ArgumentException(SR.Get("AbsoluteUriNotAllowed"));ParserContext parserContext = new ParserContext();parserContext.BaseUri = curComponentUri;Stream stream;bool closeStream;if (Application.IsComponentBeingLoadedFromOuterLoadBaml(curComponentUri)){NestedBamlLoadInfo nestedBamlLoadInfo = Application.s_NestedBamlLoadInfo.Peek();stream = nestedBamlLoadInfo.BamlStream;stream.Seek(0L, SeekOrigin.Begin);parserContext.SkipJournaledProperties = nestedBamlLoadInfo.SkipJournaledProperties;nestedBamlLoadInfo.BamlUri = (Uri) null;closeStream = false;}else{PackagePart resourceOrContentPart = Application.GetResourceOrContentPart(resourceLocator);ContentType contentType = new ContentType(resourceOrContentPart.ContentType);stream = resourceOrContentPart.GetStream();closeStream = true;if (!MimeTypeMapper.BamlMime.AreTypeAndSubTypeEqual(contentType))throw new Exception(SR.Get("ContentTypeNotSupported", (object) contentType));}if (!(stream is IStreamInfo streamInfo) || streamInfo.Assembly != component.GetType().Assembly)throw new Exception(SR.Get("UriNotMatchWithRootType", (object) component.GetType(), (object) resourceLocator));XamlReader.LoadBaml(stream, parserContext, component, closeStream); }

? ? ? XamlReader.LoadBaml細節代碼

internal static object LoadBaml(Stream stream,ParserContext parserContext,object parent,bool closeStream) {object p1 = (object) null;EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Event.WClientParseBamlBegin, (object) parserContext.BaseUri);if (TraceMarkup.IsEnabled)TraceMarkup.Trace(TraceEventType.Start, TraceMarkup.Load);try{if (stream is IStreamInfo streamInfo2)parserContext.StreamCreatedAssembly = streamInfo2.Assembly;Baml2006ReaderSettings bamlReaderSettings = XamlReader.CreateBamlReaderSettings();bamlReaderSettings.BaseUri = parserContext.BaseUri;bamlReaderSettings.LocalAssembly = streamInfo2.Assembly;if (bamlReaderSettings.BaseUri == (Uri) null || string.IsNullOrEmpty(bamlReaderSettings.BaseUri.ToString()))bamlReaderSettings.BaseUri = BaseUriHelper.PackAppBaseUri;Baml2006ReaderInternal baml2006ReaderInternal = new Baml2006ReaderInternal(stream, new Baml2006SchemaContext(bamlReaderSettings.LocalAssembly), bamlReaderSettings, parent);Type type = (Type) null;if (streamInfo2.Assembly != (Assembly) null){try{type = XamlTypeMapper.GetInternalTypeHelperTypeFromAssembly(parserContext);}catch (Exception ex){if (CriticalExceptions.IsCriticalException(ex))throw;}}if (type != (Type) null){XamlAccessLevel xamlAccessLevel = XamlAccessLevel.AssemblyAccessTo(streamInfo2.Assembly);new XamlLoadPermission(xamlAccessLevel).Assert();try{p1 = WpfXamlLoader.LoadBaml((System.Xaml.XamlReader) baml2006ReaderInternal, parserContext.SkipJournaledProperties, parent, xamlAccessLevel, parserContext.BaseUri);}finally{CodeAccessPermission.RevertAssert();}}elsep1 = WpfXamlLoader.LoadBaml((System.Xaml.XamlReader) baml2006ReaderInternal, parserContext.SkipJournaledProperties, parent, (XamlAccessLevel) null, parserContext.BaseUri);if (p1 is DependencyObject dependencyObject2)dependencyObject2.SetValue(BaseUriHelper.BaseUriProperty, (object) bamlReaderSettings.BaseUri);if (p1 is Application application2)application2.ApplicationMarkupBaseUri = XamlReader.GetBaseUri(bamlReaderSettings.BaseUri);}finally{if (TraceMarkup.IsEnabled)TraceMarkup.Trace(TraceEventType.Stop, TraceMarkup.Load, p1);EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Event.WClientParseBamlEnd, (object) parserContext.BaseUri);if (closeStream && stream != null)stream.Close();}return p1; }
  • 4.加載控件對象

提取BAML(編譯過的XAML)解析并創建每個定義的控件對象,設置屬性、關聯事件等內容。

internal static object LoadBamlStreamWithSyncInfo(Stream stream, ParserContext pc) {if (Application.s_NestedBamlLoadInfo == null)Application.s_NestedBamlLoadInfo = new Stack<NestedBamlLoadInfo>();NestedBamlLoadInfo nestedBamlLoadInfo = new NestedBamlLoadInfo(pc.BaseUri, stream, pc.SkipJournaledProperties);Application.s_NestedBamlLoadInfo.Push(nestedBamlLoadInfo);try{return XamlReader.LoadBaml(stream, pc, (object) null, true);}finally{Application.s_NestedBamlLoadInfo.Pop();if (Application.s_NestedBamlLoadInfo.Count == 0)Application.s_NestedBamlLoadInfo = (Stack<NestedBamlLoadInfo>) null;} }

循環遍歷所有xaml里的標簽節點生成窗體內的內容。

private static object Load(System.Xaml.XamlReader xamlReader,IXamlObjectWriterFactory writerFactory,bool skipJournaledProperties,object rootObject,XamlObjectWriterSettings settings,Uri baseUri) {XamlContextStack<WpfXamlFrame> stack = new XamlContextStack<WpfXamlFrame>((Func<WpfXamlFrame>) (() => new WpfXamlFrame()));int persistId = 1;settings.AfterBeginInitHandler = (EventHandler<XamlObjectEventArgs>) ((sender, args) =>{if (EventTrace.IsEnabled(EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose)){IXamlLineInfo xamlLineInfo = xamlReader as IXamlLineInfo;int num1 = -1;int num2 = -1;if (xamlLineInfo != null && xamlLineInfo.HasLineInfo){num1 = xamlLineInfo.LineNumber;num2 = xamlLineInfo.LinePosition;}int num3 = (int) EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientParseXamlBamlInfo, EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, (object) (args.Instance == null ? 0L : PerfService.GetPerfElementID(args.Instance)), (object) num1, (object) num2);}if (args.Instance is UIElement instance3){int num = persistId++;instance3.SetPersistId(num);}XamlSourceInfoHelper.SetXamlSourceInfo(args.Instance, args, baseUri);if (args.Instance is DependencyObject instance4 && stack.CurrentFrame.XmlnsDictionary != null){XmlnsDictionary xmlnsDictionary = stack.CurrentFrame.XmlnsDictionary;xmlnsDictionary.Seal();XmlAttributeProperties.SetXmlnsDictionary(instance4, xmlnsDictionary);}stack.CurrentFrame.Instance = args.Instance;});XamlObjectWriter xamlWriter = writerFactory == null ? new XamlObjectWriter(xamlReader.SchemaContext, settings) : writerFactory.GetXamlObjectWriter(settings);IXamlLineInfo xamlLineInfo1 = (IXamlLineInfo) null;try{xamlLineInfo1 = xamlReader as IXamlLineInfo;IXamlLineInfoConsumer xamlLineInfoConsumer = (IXamlLineInfoConsumer) xamlWriter;bool shouldPassLineNumberInfo = false;if (xamlLineInfo1 != null && xamlLineInfo1.HasLineInfo && xamlLineInfoConsumer != null && xamlLineInfoConsumer.ShouldProvideLineInfo)shouldPassLineNumberInfo = true;IStyleConnector styleConnector = rootObject as IStyleConnector;WpfXamlLoader.TransformNodes(xamlReader, xamlWriter, false, skipJournaledProperties, shouldPassLineNumberInfo, xamlLineInfo1, xamlLineInfoConsumer, stack, styleConnector);xamlWriter.Close();return xamlWriter.Result;}catch (Exception ex){if (CriticalExceptions.IsCriticalException(ex) || !XamlReader.ShouldReWrapException(ex, baseUri)){throw;}else{XamlReader.RewrapException(ex, xamlLineInfo1, baseUri);return (object) null;}} }// Get the XAML content from an external file. DependencyObject rootElement; using (FileStream fs = new FileStrearn(xamlFile, FileMode Open)){ rootElement = (DependencyObject)XamlReader.Load(fs); }// Insert the markup into this window. this.Content = rootElement; // Find the control with the appropriate buttonl = (Button)LogicalTreeHelper.FindLogicalNode(rootElement, ibuttonl"); name. // Wire up the event handler. buttonl.Click += buttonl 'Click

【截選內容1,這一段引用lindexi文章內的內容,原文地址在文章末尾】在 WPF 中,在 XAML 里面定義的對象的創建,實際上不是完全通過反射來進行創建的,在WPF框架里面,有進行了一系列的優化。將會通過 XamlTypeInvoker 的 CreateInstance 方法來進行對象的創建,而默認的 XamlTypeInvoker 的 CreateInstance 定義如下。還有其他精彩內容在原文里可以查看;

public virtual object CreateInstance(object[] arguments){ThrowIfUnknown();if (!_xamlType.UnderlyingType.IsValueType && (arguments == null || arguments.Length == 0)){object result = DefaultCtorXamlActivator.CreateInstance(this);if (result != null){return result;}}return CreateInstanceWithActivator(_xamlType.UnderlyingType, arguments);}private object CreateInstanceWithActivator(Type type, object[] arguments){return SafeReflectionInvoker.CreateInstance(type, arguments);}

【截選內容2,這一段引用lindexi文章內的內容,原文地址在文章末尾】

在 EnsureConstructorDelegate 方法里面將會判斷如果對象是公開的,那么嘗試獲取默認構造函數,將默認構造函數做成委托。此時的性能將會是類型第一次進入的時候的速度比較慢,但是后續進入的時候就能使用委托創建,此時性能將會比較好。通過反射創建委托提升性能的方法,詳細請看 .NET Core/Framework 創建委托以大幅度提高反射調用的性能 - walterlv

private static bool EnsureConstructorDelegate(XamlTypeInvoker type) {// 如果類型初始化過構造函數創建,那么返回,這是緩存的方法if (type._constructorDelegate != null){return true;}// 如果不是公開的方法,那么將無法使用反射創建委托的科技if (!type.IsPublic){return false;}// 反射獲取對象的構造函數Type underlyingType = type._xamlType.UnderlyingType.UnderlyingSystemType;// Look up public ctors only, for equivalence with Activator.CreateInstanceConstructorInfo tConstInfo = underlyingType.GetConstructor(Type.EmptyTypes);IntPtr constPtr = tConstInfo.MethodHandle.GetFunctionPointer();// 反射創建委托,這樣下次訪問就不需要使用反射,可以提升性能// This requires Reflection PermissionAction<object> ctorDelegate = ctorDelegate =(Action<object>)s_actionCtor.Invoke(new object[] { null, constPtr });type._constructorDelegate = ctorDelegate;return true; }

也就是說只有第一次的類型進入才會調用反射創建委托用來提升性能,之后的進入將會使用第一次創建出來的委托來創建對象,這樣能提升性能。

4.Reference

dotnet/wpf: WPF is a .NET Core UI framework for building Windows desktop applications. (github.com)

dotnet 讀 WPF 源代碼筆記 XAML 創建對象的方法 (lindexi.com)

總結

以上是生活随笔為你收集整理的解读WPF中的Xaml的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩欧美在线看 | 亚洲精品免费电影 | 青青艹在线观看 | 欧美日韩亚洲国产另类 | 成人国产精品免费 | 亚洲精品福利视频 | 艳母日本动漫在线观看 | 亚洲精品专区 | 国产盗摄视频在线观看 | 在线一区二区视频 | 波多野结衣久久精品 | 天天干天天操天天插 | 日韩性网 | 福利在线播放 | 天天射夜夜撸 | 99精品视频免费版的特色功能 | 麻豆传媒网站在线观看 | 人妻aⅴ无码一区二区三区 阿v免费视频 | 日韩综合第一页 | 国产一级片久久 | 亚洲乱码一区二区 | 国产精品黄色在线观看 | 手机在线中文字幕 | 日韩美女免费线视频 | 欧美熟妇久久久久 | 色综合一区二区三区 | 丁香免费视频 | 双性懵懂美人被强制调教 | 亚洲一区二区观看播放 | 精品视频导航 | 极品一区 | 91一区二区三区 | 女人扒开双腿让男人捅 | 亚洲调教 | 国产不卡视频在线 | 中国女人内谢69xxxxⅹ视频 | 亚洲伊人影院 | 成年人毛片视频 | 欧美性猛交乱大交xxxx | 人妻在客厅被c的呻吟 | 丁香六月综合 | 成人在线a | 狠狠爱网站 | av中文字幕免费在线观看 | 成人影片在线免费观看 | 久久er99热精品一区二区 | 19禁大尺度做爰无遮挡电影 | 男人喷出精子视频 | 大片视频免费观看视频 | 日本午夜精品理论片a级app发布 | 女十八毛片 | 国产成人在线视频网站 | 久久a毛片 | 中文字幕综合在线 | 亚洲精品男女 | 日本黄色录相 | 99热官网| 成人精品一区二区三区中文字幕 | 成人毛片av | a∨视频 | 一级黄色av片 | 亚洲精品乱码久久久久99 | 人妻精品一区 | 亚洲成a人在线观看 | 午夜激情视频网 | 99久久国产宗和精品1上映 | 免费日韩| 高跟av| 欧美激情h | 久久久香蕉视频 | 欧美日韩在线视频免费播放 | 成人福利视频在线 | 黄色片免费在线 | 日本成人在线免费 | 中文字幕丝袜 | 不卡的av在线播放 | 日韩中文字幕av在线 | 尤物国产视频 | 国产性生活视频 | 国产视频一区二区三区在线观看 | 国产欧美精品在线观看 | 亚洲av少妇一区二区在线观看 | 国产精品黄色 | 欧美亚洲影院 | 免费在线色 | 影音先锋激情在线 | 国产另类专区 | 五月婷视频 | 男女插孔视频 | 高h喷水荡肉少妇爽多p视频 | 99爱视频在线观看 | 白峰美羽在线播放 | 成人福利视频网站 | 小毛片在线观看 | 高清毛片aaaaaaaaa片 | 国外成人在线视频 | 国产精久久久 | a级片免费在线观看 | 国产伦精品一区二区三区妓女下载 |