国产自产第一-国产自产对白一区-国产自产精品-国产自产区44页-国产自产在线-国产自产自拍-国产自产自拍视频-国产自精品

金喜正规买球

WPF基礎到企業應用系列7——深入剖析依賴屬性(WPF/Silverlight核心)

轉帖|其它|編輯:郝浩|2010-11-03 14:23:15.000|閱讀 1302 次

概述:前幾篇我們講了WPF的一些基本知識,但是始終沒有接觸最核心的概念,那么從這篇文章開始的下面幾篇文章中,我們會分別深入討論一下依賴屬性、路由事件、命令和綁定等相關概念,希望這幾篇文章對大家能有所幫助。由于自己才疏學淺且是對這些技術的使用總結和心得體會,錯誤之處在所難免,懷著技術交流的心態,在這里發表出來,所以也希望大家能夠多多指點,這樣在使一部分人受益的同時也能糾正我的錯誤觀點,以便和各位共同提高。

# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>

一. 摘要

  首先圣殿騎士很高興這個系列能得到大家的關注和支持,這個系列從七月份開始到現在才第七篇,上一篇發布是在8月2日,掐指一算有二十多天沒有繼續更新了,最主要原因一來是想把它寫好,二來是因為最近幾個月在籌備“云計算之旅”系列,所以一再推遲了發布進度。之前一直都沒有想過要錄制視頻,主要的原因還是怕自己知識有限,從而誤導他人,所以前幾次浪曦和51CTO邀請錄制視頻,我都以工作忙、公司內部培訓需要時間和自己有待提高等理由委婉的拒絕了,說實在的,自己也知道自己還有很多地方有待提高,還需要向各位學習,所以這幾年都會一直努力,相信總有一天自己頭上也會長出兩只角的。錄制視頻的事也就這樣不了了之了,直到前一段時間MSDN WebCast的再三邀請,我才決定努力試一試,同時也希望各位能夠支持,現在都把社區當成自己的堅強后盾了,所以我打算先以博客的形式發布,這樣就可以先和大家一起討論,糾正自己的某些錯誤認識,這樣在錄制視頻的時候就不會誤導他人了。

  前幾篇我們講了WPF的一些基本知識,但是始終沒有接觸最核心的概念,那么從這篇文章開始的下面幾篇文章中,我們會分別深入討論一下依賴屬性、路由事件、命令和綁定等相關概念,希望這幾篇文章對大家能有所幫助。由于自己才疏學淺且是對這些技術的使用總結和心得體會,錯誤之處在所難免,懷著技術交流的心態,在這里發表出來,所以也希望大家能夠多多指點,這樣在使一部分人受益的同時也能糾正我的錯誤觀點,以便和各位共同提高。

  這篇文章比較多,在開篇之前我們會先介紹比本篇更重要的一些東西,然后插播一段“云計算之旅”的廣告( 這里廣告費比較貴喲!),作為最近幾個月執著研究的東西,終于可以和大家見面了,希望自己能從實踐中深入淺出的講明白。在前面的兩個內容之后我們正式進入本篇的主題——依賴屬性。依賴屬性是WPF的核心概念,所以我們花費了大量的時間和篇幅進行論述,首先從依賴屬性基本介紹講起,然后過渡到依賴屬性的優先級、附加屬性、只讀依賴屬性、依賴屬性元數據、依賴屬性回調、驗證及強制值、依賴屬性監聽、代碼段(自動生成) 等相關知識,最后我們會模擬一個WPF依賴屬性的實現,來看看它里面的內部究竟是怎樣處理的,這樣就可以幫助我們更好的認清它的本質,出現問題的時候我們也可以根據原理快速找到原因了。

二. 本文提綱

  · 1.摘要

  · 2.本文提綱

  · 3.比這篇文章更重要的東西

  · 4.云計算廣告插播

  · 5.依賴屬性基本介紹

  · 6.依賴屬性的優先級

  · 7.依賴屬性的繼承

  · 8.只讀依賴屬性

  · 9.附加屬性

  · 10.清除本地值

  · 11.依賴屬性元數據

  · 12.依賴屬性回調、驗證及強制值

  · 13.依賴屬性監聽

  · 14.代碼段(自動生成)

  · 15.模擬依賴屬性實現

  · 16.本文總結

  · 17.相關代碼下載

  · 18.系列進度

三. 比這篇文章更重要的東西

  在講這篇文章之前,我們先來聊一點更重要的東西,正所謂“授人與魚不如授人以漁”,那么我們這個“漁”究竟是什么呢?大家做軟件也有不少年了,對自己擅長的一門或多門技術都有自己的經驗和心得,但總的來說可以分為向內和向外以及擴展三個方面(這里只針對.NET平臺):

(一)向外:

  會使用ASP.NET、WinForm、ASP.NET MVC、WPF、Silverlight、WF、WCF等技術,在用這些技術做項目的同時積累了較豐富的經驗,那么大家就可以形成自己的一套開發知識庫,知道這些技術怎么能快速搭建企業所需要的應用、知道這些技術在使用中會出現什么樣的問題以及如何解決。那么在這個時候你就可能已經在團隊中起到比較核心的作用,如果項目經理給你一個任務,你也可以很輕松且高效的勝任,同時在項目當中由于你也比較清楚業務邏輯,所以當機會來臨的時候,你很快會成為團隊的骨干,逐漸你就會帶幾個初級一點的工程師一起做項目;如果你不喜歡帶團隊,你就會成為資深的高級開發或者架構師。那么在向外方面我個人認為最重要的是積累經驗,對常見的應用要比較熟悉且有自己總結的一套開發庫——比如對普通的網站、電子商務系統、ERP、OA、客戶端應用等等有比較豐富的經驗。

(二)向內:

  在前面你使用了這些技術開發項目之后,你會遇到很多問題,為了解決這些問題,你會逐漸研究一些比較底層次的東西。比如對于ASP.NET,你會逐漸的去深入理解ASP.NET的整個處理過程、頁面的生命周期、自定義控件的開發等等,由于自己最初是由C、C++、Java這樣過渡到.NET的,所以對一些細節總喜歡鉆牛角尖,這也浪費了不少時間,但同時也得到了很多意外之喜。

  對于C#語言上,你也會逐漸去刨根問底,想看看這些語法糖背后到底隱藏著什么秘密,很多對.NET技術比較癡迷的人都會選擇對C# 1.0 語言通過IL代碼來深層次認識,然后對C#2.0、C#3.0、C#4.0都編譯為C# 1.0 來學習,這樣他們就能認識到語言的內部到底是怎么執行的,正所謂知道的同時也知道其所以然。

  對于WF,你不僅要知道各 Activity的使用,你也得知道其內部的原理,比如WF 內部就是依靠依賴屬性來在工作流中的各 Activity 間傳遞屬性值的,如果你細心,你還原WF的依賴屬性源碼,你會發現它和WPF、Silverlight中的依賴屬性大同小異,原理基本一樣、只是針對特定技術進行了適當的調整。

  對于數據底層操作也一樣,不管你是用的拼接SQL、存儲過程、IBATIS.NET、Nhibernate,Active Record,Linq to sql、Entity framework還是自己開發的ORM組件,你得明白它內部的原理,你要知道這些開源的代碼還是很值得研究的,我的經驗是先熟練使用這些功能,然后再剖析它的源碼,然后自己寫一套自己的框架,現在我也在精簡自己的ORM框架,因為之前把重點放在了實現盡可能多的功能,所以對性能等細節沒有做過多優化,后面也會向大家慢慢學習。

  對WPF和Silverlight一樣,你不僅要知道怎么用這些技術,你要知道它的原理,比如對依賴屬性,你知道它的內部原理,就可以對平時出現的諸如我設置的值怎么沒有起作用、我Binding的元素怎么沒有出現等等問題; 對路由事件,你也會經常遇到我的事件怎么沒有執行、我的自定義控件事件怎么處理不對、路由傳遞怎么沒有起作用等等,這個時候你如果深入理解了路由事件的內部處理,這些問題就迎刃而解了;對WPF和Silverlight新多出來的命令特性,大家很多時候也是比較疑惑,也會遇到命令失效等等問題,其實如果你深入的了解了它的原理,你就會知道,它其實在內部也是事件,只不過微軟在里面做了很多封裝而已;對Binding就更是如此,我們也不想在這篇文章談開去,畢竟在下面的幾篇文章會詳細的對這些技術進行涉及。

(三)擴展:

  通過前面的向內和向外的修煉以后,接下來要做的就是不斷實踐,不斷總結經驗,在這個過程中更重要的是要懂得分享,有分享才會使自己和他人共同提高,有分享才能讓自己擺脫狂妄的井底之蛙思想,還記得自己剛做技術的一兩年里,天天喜歡提及大型架構、大型數據處理、操作系統底層代碼如何如何,甚至把AOP、IOC、SSH、OO及設計模式、SOA等詞語時常掛在嘴邊,生怕別人不知道自己不懂。但隨著自己技術實質上的提高以及經驗的積累,自己也就逐漸成熟起來,對這些技術逐漸深入理解且理解了其內部實現原理,這樣反而自己變得謙虛起來了,對之前的那些思想感到無比的羞愧。同時也明白自己在慢慢成長了,現在都習慣戲稱自己為打雜工,其實更多時候用打字員會合理一些,所以希望大家能多多指教,這樣我才能更快地擺脫打字員的生活。我在這里也對擴展做一點小的總結:

  記錄學習:這是學習很重要的一步,你不一定要寫技術博客,你也可以做一些例子來記錄,你也可以在學習之后寫一個總結,畢竟人的精力十分有限,在很多時候,它并不能像硬盤一樣存儲起來就不會丟失,更多的時候它更像一塊內存。

  同道交流:在這一層里我覺得最重要的就是和一些技術較好的人成為朋友,和他們經常探討一些技術,這樣可以縮短學習的周期,同時也能快速的解決問題,畢竟人的精力十分有限,你沒有遇到過的問題,說不定其他人遇到過。在這方面自己也體會頗深,也很感謝之前幾個公司及現在公司的同事、社區朋友以及一些志同道合之士,感謝你們的指點,沒有你們的指點,我也不可能從小鳥進化成逐鹿程序界的菜鳥,我也為自己能成為一只老菜鳥感到自豪!

  少考證、多務實:在擴展的這一層里,我們要謹記不要為了考證而去考證,那樣是沒有任何實際作用的。對MVP也一樣,一切順其自然為好,記得大學時候身邊就有人連續四次榮獲MVP稱號,這叫我在當時是相當的佩服,在佩服之余我們要切記務實,沒有務實的東西都是很虛擬飄渺的。還記得自己當初在大學里面受到考證風氣的影響,神經兮兮的去考過了什么國家計算機四級和MCP等一大堆證件,后來到公司面試興高采烈拿著20多張證書,才知道那些東西根本就沒有什么價值,反而讓自己去學習了最不喜歡的技術,同時也給自己掛上了考證族的名號。所以后來總結就是勞民傷財、徒添傷悲!

  技術分享:在自己公司及其他公司進行一些技術培訓或者討論,其實重要的不是什么榮譽,而是在把這個培訓看成是一些技術交流和分享,因為在這個過程中,你可能會重新認識你所掌握的技術、你可能會遇到一些志同道合的人、你可能會在分享過程中糾正以前的錯誤認識、你可能會在各方面得到提高從而完善自己的知識體系,但是最重要的是你要認真對待每一次培訓,知之為知之不知為不知,不要不能教導他人反而誤導了他人。記得有一次在公司培訓OO與設計模式,我知道這個專題想在一下午的時間把它講清楚是非常困難的,這個不像之后培訓的WPF、WCF和Silverlight那么單純,并且每個人的基礎都不一樣,當中有還沒有畢業的實習生、剛畢業不久的畢業生、工作了數年的工程師及技術大牛們,所以如何把這些知識很好的插入到每個人的知識樹上面成了我考慮的重點。同時我的心里也比較矛盾,一方面希望參加培訓的同事多一些,另一方面希望人越少越好。前者則是按照常理來考慮的,畢竟培訓者都希望自己培訓,越受歡迎越好,這樣才能使自己的思想得到更多人的認可,自己也能實現分享知識的目的。后者則是擔心怕講不好,少一點人就少一點罪過。可是恰巧這一次是歷次培訓中最多的一次,來參加培訓的同事有一百多人,不過幸好由于會議室坐不下,才分成了兩批,這樣就可以讓我具備了更充分的時間和更好的心態。總之培訓是向內和向外的提煉與升華,正所謂“自己理解的知識未必能使人家理解”,這不僅考驗的是技術,還考驗了一個人的綜合能力。

(四)結論:

  前面從向內和向外以及擴展三個方面進行了簡單闡述,用一句話概括就是:向內深不可測、向外漫無邊際、擴展才能超越極限。由于這里只是對本文及下面的三篇文章做一些鋪墊工作,所以我們也不細細分解,那么我也得稍微推薦一點資料才對得起大家:第一還是研究微軟的類庫,對我們常見的應用進行研究,可以結合Reflector+VS調試內部代碼功能一起研究(IL能幫我們看清楚一些內部原理,但是不推薦細究,因為它會浪費我們很多時間,畢竟是微軟搞出來的這么一套東西,說不定微軟哪天就換了)。其次就是研究MONO源碼(),這個是個非常好的東西,對.NET的功能大部分都進行了實現,我之前研究它不是因為它的跨平臺,是感興趣它的源碼,大家也可以在線查看它的源碼(),說到java2s這個網站,也是我平時去得比較多的網站,因為它比較全面和方便,同時也會給我們帶來意想不到的收獲。再其次就是研究一些開源的框架和項目,比如pet shop 4.0()、BlogEngine.NET()、Spring.NET()、Castle()、log4net()、NHibernate()、iBATIS.NET()、Caliburn()、MVVM Light Toolkit()、Prism()等等。這里要注意的是:在研究的過程中一定要先熟悉功能,再研究它內部的源碼和實現,然后再創造出自己的框架。這樣才能激發我們研究的欲望,才會產生作用和反作用力,從而才會使我們真正受益。

四. 云計算廣告插播

  由于這段時間白天要研究云計算專題(公司項目原因,最主要還是自己的興趣使然),晚上和閑暇時間又要寫WPF,所以感覺有點心猿意馬。原打算寫完WPF這個系列以后才繼續”云計算之旅“這個系列,但是經過慎重的思考,同時也考慮到錄制MSDN WebCast視頻,所以決定兩個系列同時進行,經過幾個月的籌備(期間包括折騰公司的云計算項目、研究相關云計算的電子書、國外技術視頻和國外各技術社區和博客等),自己也頗有收獲。期間最重要的還是自己寫例子,寫完了以后再分析它的原理直至最后總結,這樣才能把它變成自己的東西,現在回過頭來感覺云計算終于在自己心目中走下了神壇,逐漸揭開了那一層神秘面紗,所以才有下面這個系列的分享,也希望大家能給出建議,從而達到技術交流、共同提高的目的。

云計算之旅1—開篇有益

云計算之旅2—云計算總覽

云計算之旅3—云計算提供商綜合對比

云計算之旅4—Windows Azure總覽

云計算之旅5—第一個Windows Azure程序

云計算之旅6—剖析Windows Azure程序內部原理

云計算之旅7—ASP.NET Web Role

云計算之旅8—ASP.NET MVC Web Role

云計算之旅9—WCF Service Web Role

云計算之旅10—Work Role Castle

云計算之旅11—CGI Web Role

云計算之旅12—云存儲之Blob

云計算之旅13—云存儲之Table

云計算之旅14—云存儲之Quee

云計算之旅15—云存儲之Dive

云計算之旅16—SQL Azure(一)

云計算之旅17—SQL Azure(二)

云計算之旅18—SQL Azure(三)

云計算之旅19—AppFabric(一)

云計算之旅20—AppFabric(二)

云計算之旅21—AppFabric(三)

云計算之旅22—云平臺安全問題

云計算之旅23—老技術兼容問題

云計算之旅24—ASP.NET+SQL項目移植到云平臺

云計算之旅25—WinForm/WPF項目移植到云平臺(云/端模式)

云計算之旅26—ASP.NET+Silverlight項目移植到云平臺

云計算之旅27—Amazon云計算

云計算之旅28—Google云計算

云計算之旅29—SalesForce云計算

云計算之旅30—云計算開發總結

  上面的分類是按照最近學習的總結歸類的,在這幾個月中也先后寫了一些文章和代碼示例,同時有些知識沒有羅列上去,在后面可能會有一些小的修改。總之,我們堅決抵制”忽悠“,爭取以實際代碼說話,在此過程中希望大家能夠積極踴躍的加入進來,如果有什么不對的地方,也希望向大家學習,最重要的是大家有所收獲就好!

五. 依賴屬性基本介紹

  前面廢話了這么久,到現在才真正進入今天的主題,對此感到非常抱歉,如果各位不喜歡,可以直接跳到這里閱讀。大家都知道WPF帶來了很多新的特性,它的一大亮點是引入了一種新的屬性機制——依賴屬性。依賴屬性基本應用在了WPF的所有需要設置屬性的元素。依賴屬性根據多個提供對象來決定它的值(可以是動畫、父類元素、綁定、樣式和模板等),同時這個值也能及時響應變化。所以WPF擁有了依賴屬性后,代碼寫起來就比較得心應手,功能實現上也變得非常容易了。如果沒有依賴屬性,我們將不得不編寫大量的代碼。關于WPF的依賴屬性,主要有下面三個優點,我們的研究也重點放在這三點上:
1、新功能的引入:加入了屬性變化通知,限制、驗證等等功能,這樣就可以使我們更方便的實現我們的應用,同時也使代碼量大大減少了,許多之前不可能的功能都可以輕松的實現了。
2、節約內存:在WinForm等項目開發中,你會發現UI控件的屬性通常都是賦予的初始值,為每一個屬性存儲一個字段將是對內存的巨大浪費。WPF依賴屬性解決了這個問題,它內部使用高效的稀疏存儲系統,僅僅存儲改變了的屬性,即默認值在依賴屬性中只存儲一次。
3、支持多個提供對象:我們可以通過多種方式來設置依賴屬性的值。同時其內部可以儲存多個值,配合Expression、Style、Animation等可以給我們帶來很強的開發體驗。
在.NET當中,屬性是我們很熟悉的,封裝類的字段,表示類的狀態,編譯后被轉化為對應的get和set方法(在JAVA里面沒有屬性的概念,通常都是寫相應的方法來對字段進行封裝)。屬性可以被類或結構等使用。 一個簡單的屬性如下,也是我們常用的寫法:

private string sampleProperty;
public string SampleProperty
{
get
{
return sampleProperty;
}
set
{
if (value != null)
{
sampleProperty = value;
}
else
{
sampleProperty = "Knights Warrior!";
}
}
}

屬性是我們再熟悉不過的了,那么究竟依賴屬性怎么寫呢?依賴屬性和屬性到底有什么區別和聯系呢?其實依賴屬性的實現很簡單,只要做以下步驟就可以實現:
第一步: 讓所在類型繼承自 DependencyObject基類,在WPF中,我們仔細觀察框架的類圖結構,你會發現幾乎所有的 WPF 控件都間接繼承自DependencyObject類型。
第二步:使用 public static 聲明一個 DependencyProperty的變量,該變量才是真正的依賴屬性 ,看源碼就知道這里其實用了簡單的單例模式的原理進行了封裝(構造函數私有),只暴露Register方法給外部調用。
第三步:在靜態構造函數中完成依賴屬性的元數據注冊,并獲取對象引用,看代碼就知道是把剛才聲明的依賴屬性放入到一個類似于容器的地方,沒有講實現原理之前,請容許我先這么陳述。
第四步:在前面的三步中,我們完成了一個依賴屬性的注冊,那么我們怎樣才能對這個依賴屬性進行讀寫呢?答案就是提供一個依賴屬性的實例化包裝屬性,通過這個屬性來實現具體的讀寫操作。

根據前面的四步操作,我們就可以寫出下面的代碼:

public class SampleDPClass : DependencyObject
{
//聲明一個靜態只讀的DependencyProperty字段
public static readonly DependencyProperty SampleProperty;
static SampleDPClass()
{
//注冊我們定義的依賴屬性Sample
SampleProperty = DependencyProperty.Register("Sample", typeof(string), typeof(SampleDPClass),
new PropertyMetadata("Knights Warrior!", OnValueChanged));
} private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
//當值改變時,我們可以在此做一些邏輯處理
}
//屬性包裝器,通過它來讀取和設置我們剛才注冊的依賴屬性
public string Sample
{
get{ return (string)GetValue(SampleProperty);
}
set { SetValue(SampleProperty, value);
}
}
}

總結:我們一般.NET屬性是直接對類的一個私有屬性進行封裝,所以讀取值的時候,也就是直接讀取這個字段;而依賴屬性則是通過調用繼承自DependencyObject的GetValue()和SetValue來進行操作,它實際存儲在DependencyProperty的一個IDictionary的鍵-值配對字典中,所以一條記錄中的鍵(Key)就是該屬性的HashCode值,而值(Value)則是我們注冊的DependencyProperty。

六. 依賴屬性的優先級

  由于WPF 允許我們可以在多個地方設置依賴屬性的值,所以我們就必須要用一個標準來保證值的優先級別。比如下面的例子中,我們在三個地方設置了按鈕的背景顏色,那么哪一個設置才會是最終的結果呢?是Black、Red還是Azure呢?

<Window x:Class="WpfApplication1.Window1"
xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="//schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Button x:Name="myButton" Background="Azure">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Black"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
Click
</Button>
</Grid>
</Window>
 

通過前面的簡單介紹,我們了解了簡單的依賴屬性,每次訪問一個依賴屬性,它內部會按照下面的順序由高到底處理該值。詳細見下圖

  

  由于這個流程圖偏理想化,很多時候我們會遇到各種各樣的問題,這里也不可能一句話、兩句話就能夠把它徹底說清楚,所以我們就不過多糾纏。等遇到問題之后要仔細分析,在找到原因之后也要不斷總結、舉一反三,只有這樣才能逐漸提高。

七. 依賴屬性的繼承

  依賴屬性繼承的最初意愿是父元素的相關設置會自動傳遞給所有層次的子元素 ,即元素可以從其在樹中的父級繼承依賴項屬性的值。這個我們在編程當中接觸得比較多,如當我們修改窗體父容器控件的字體設置時,所有級別的子控件都將自動使用該字體設置 (前提是該子控件未做自定義設置),如下面的代碼:

<Window x:Class="Using_Inherited_Dps.Window1"
xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="//schemas.microsoft.com/winfx/2006/xaml"
WindowStartupLocation="CenterScreen"
FontSize="20"
Title="依賴屬性的繼承" Height="400" Width="578">
<StackPanel >
<Label Content="繼承自Window的FontSize" />
<Label Content="重寫了繼承"
TextElement.FontSize="36"/>
<StatusBar>沒有繼承自Window的FontSize,Statusbar</StatusBar>
</StackPanel>
</Window> 
 

  Window.FontSize 設置會影響所有的內部元素字體大小,這就是所謂的屬性值繼承,如上面代碼中的第一個Label沒有定義FontSize ,所以它繼承了Window.FontSize的值。但一旦子元素提供了顯式設置,這種繼承就會被打斷,如第二個Label定義了自己的FontSize,所以這個時候繼承的值就不會再起作用了。

  這個時候你會發現一個很奇怪的問題:雖然StatusBar沒有重寫FontSize,同時它也是Window的子元素,但是它的字體大小卻沒有變化,保持了系統默認值。那這是什么原因呢?作為初學者可能都很納悶,官方不是說了原則是這樣的,為什么會出現表里不一的情況呢?其實仔細研究才發現并不是所有的元素都支持屬性值繼承。還會存在一些意外的情況,那么總的來說是由于以下兩個方面:

1、有些Dependency屬性在用注冊的時候時指定Inherits為不可繼承,這樣繼承就會失效了。

2、有其他更優先級的設置設置了該值,在前面講的的“依賴屬性的優先級”你可以看到具體的優先級別。

  這里的原因是部分控件如StatusBar、Tooptip和Menu等內部設置它們的字體屬性值以匹配當前系統。這樣用戶通過操作系統的控制面板來修改它們的外觀。這種方法存在一個問題:StatusBar等截獲了從父元素繼承來的屬性,并且不影響其子元素。比如,如果我們在StatusBar中添加了一個Button。那么這個Button的字體屬性會因為StatusBar的截斷而沒有任何改變,將保留其默認值。所以大家在使用的時候要特別注意這些問題。

 

前面我們看了依賴屬性的繼承,當我們自定義的依賴屬性,應該如何處理繼承的關系呢? 請看下面的代碼(注釋很詳細,我就不再費口水了):

public class MyCustomButton : Button
{
static MyCustomButton()
{
//通過MyStackPanel依賴屬性MinDateProperty的AddOwner方式實現繼承,注意FrameworkPropertyMetadataOptions的值為Inherits
MinDateProperty = MyStackPanel.MinDateProperty.AddOwner(typeof(MyCustomButton),
new FrameworkPropertyMetadata(DateTime.MinValue, FrameworkPropertyMetadataOptions.Inherits));
}

public static readonly DependencyProperty MinDateProperty;

public DateTime MinDate
{
get { return (DateTime)GetValue(MinDateProperty); }
set { SetValue(MinDateProperty, value); }
}
}


public class MyStackPanel : StackPanel
{
static MyStackPanel()
{
//我們在MyStackPanel里面注冊了MinDate,注意FrameworkPropertyMetadataOptions的值為Inherits
MinDateProperty = DependencyProperty.Register("MinDate",
typeof(DateTime),
typeof(MyStackPanel),
new FrameworkPropertyMetadata(DateTime.MinValue, FrameworkPropertyMetadataOptions.Inherits));
}

public static readonly DependencyProperty MinDateProperty;

public DateTime MinDate
{
get { return (DateTime)GetValue(MinDateProperty); }
set { SetValue(MinDateProperty, value); }
}
}

那么就可以在XAML中進行使用了

<Window x:Class="Custom_Inherited_DPs.Window1"
xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="//schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Custom_Inherited_DPs"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
WindowStartupLocation="CenterScreen"
Title="使用自動以依賴屬性繼承" Height="300" Width="300">
<Grid>
<local:MyStackPanel x:Name="myStackPanel" MinDate="{x:Static sys:DateTime.Now}">
<!-- myStackPanel的依賴屬性 -->
<ContentPresenter Content="{Binding Path=MinDate, ElementName=myStackPanel}"/>
<!-- 繼承自myStackPanel的依賴屬性 -->
<local:MyCustomButton
Content="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=MinDate}"
Height="20"/>
</local:MyStackPanel>
</Grid>
</Window>

最后的效果如下:

 

八. 只讀依賴屬性

  我們以前在對簡單屬性的封裝中,經常會對那些希望暴露給外界只讀操作的字段封裝成只讀屬性,同樣在WPF中也提供了只讀屬性的概念,如一些WPF控件的依賴屬性是只讀的,它們經常用于報告控件的狀態和信息,像IsMouseOver等屬性, 那么在這個時候對它賦值就沒有意義了。 或許你也會有這樣的疑問:為什么不使用一般的.Net屬性提供出來呢?一般的屬性也可以綁定到元素上呀?這個是由于有些地方必須要用到只讀依賴屬性,比如Trigger等,同時也因為內部可能有多個提供者修改其值,所以用.Net屬性就不能完成天之大任了。
那么一個只讀依賴屬性怎么創建呢?其實創建一個只讀的依賴屬性和創建一個一般的依賴屬性大同小異(研究源碼你會發現,其內部都是調用的同一個Register方法)。僅僅是用DependencyProperty.RegisterReadonly替換了DependencyProperty.DependencyProperty而已。和前面的普通依賴屬性一樣,它將返回一個DependencyPropertyKey。該鍵值在類的內部暴露一個賦值的入口,同時只提供一個GetValue給外部,這樣便可以像一般屬性一樣使用了,只是不能在外部設置它的值罷了。

下面我們就用一個簡單的例子來概括一下:

public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();

//內部用SetValue的方式來設置值
DispatcherTimer timer =
new DispatcherTimer(TimeSpan.FromSeconds(1),
DispatcherPriority.Normal,
(object sender, EventArgs e)=>
{
int newValue = Counter == int.MaxValue ? 0 : Counter + 1;
SetValue(counterKey, newValue);
},
Dispatcher);

}

//屬性包裝器,只提供GetValue,這里你也可以設置一個private的SetValue進行限制
public int Counter
{
get { return (int)GetValue(counterKey.DependencyProperty); }
}

//用RegisterReadOnly來代替Register來注冊一個只讀的依賴屬性
private static readonly DependencyPropertyKey counterKey =
DependencyProperty.RegisterReadOnly("Counter",
typeof(int),
typeof(Window1),
new PropertyMetadata(0));
}

  
XAML中代碼:

<Window x:Name="winThis" x:Class="WpfApplication1.Window1"
xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="//schemas.microsoft.com/winfx/2006/xaml"
Title="Read-Only Dependency Property" Height="300" Width="300">
<Grid>
<Viewbox>
<TextBlock Text="{Binding ElementName=winThis, Path=Counter}" />
</Viewbox>
</Grid>
</Window>

效果如下圖所示: 

 

九. 附加屬性

  前面我們講了依賴屬性。現在我們再繼續探討另外一種特殊的Dependency屬性——附加屬性。附加屬性是一種特殊的依賴屬性。他允許給一個對象添加一個值,而該對象可能對此值一無所知。

  最好的例子就是布局面板。每一個布局面板都需要自己特有的方式來組織它的子元素。如Canvas需要Top和left來布局,DockPanel需要Dock來布局。當然你也可以寫自己的布局面板(在上一篇文章中我們對布局進行了比較細致的探討,如果有不清楚的朋友也可以再回顧一下)。

下面代碼中的Button 就是用了Canvas的Canvas.Top和Canvas.Left="20" 來進行布局定位,那么這兩個就是傳說中的附加屬性。

<Canvas>
<Button Canvas.Top="20" Canvas.Left="20" Content="Knights Warrior!"/>
</Canvas>

  在最前面的小節中,我們是使用DependencyProperty.Register來注冊一個依賴屬性,同時依賴屬性本身也對外提供了 DependencyProperty.RegisterAttached方法來注冊附加屬性。這個RegisterAttached的參數和 Register是完全一致的,那么Attached(附加)這個概念又從何而來呢?

  其實我們使用依賴屬性,一直在Attached(附加)。我們注冊(構造)一個依賴屬性,然后在DependencyObject中通過 GetValue和SetValue來操作這個依賴屬性,也就是把這個依賴屬性通過這樣的方法關聯到了這個DependencyObject上,只不過是通過封裝CLR屬性來達到的。那么RegisterAttached又是怎樣的呢?

下面我們來看一個最簡單的應用:首先我們注冊(構造)一個附加屬性

public class AttachedPropertyChildAdder
{
//通過使用RegisterAttached來注冊一個附加屬性
public static readonly DependencyProperty IsAttachedProperty =
DependencyProperty.RegisterAttached("IsAttached", typeof(bool), typeof(AttachedPropertyChildAdder),
new FrameworkPropertyMetadata((bool)false));

//通過靜態方法的形式暴露讀的操作
public static bool GetIsAttached(DependencyObject dpo)
{
return (bool)dpo.GetValue(IsAttachedProperty);
}

//通過靜態方法的形式暴露寫的操作
public static void SetIsAttached(DependencyObject dpo, bool value)
{
dpo.SetValue(IsAttachedProperty, value);
}
}

在XAML中就可以使用剛才注冊(構造)的附加屬性了:

  

  在上面的例子中,AttachedPropertyChildAdder 中并沒有對IsAttached采用CLR屬性形式進行封裝,而是使用了靜態SetIsAttached方法和GetIsAttached方法來存取IsAttached值,當然如果你了解它內部原理,你就會看到實際上還是調用的SetValue與GetValue來進行操作(只不過擁有者不同而已)。這里我們不繼續深入下去,詳細在后面的內容會揭開謎底。

十. 清除本地值

  在很多時候,由于我們的業務邏輯和UI操作比較復雜,所以一個龐大的頁面會進行很多諸如動畫、3D、多模板及樣式的操作,這個時候頁面的值已經都被改變了,如果我們想讓它返回默認值,可以用ClearValue 來清除本地值,但是遺憾的是,很多時候由于WPF依賴屬性本身的設計,它往往會不盡如人意(詳細就是依賴屬性的優先級以及依賴屬性EffectiveValueEntry 的影響)。ClearValue 方法為在元素上設置的依賴項屬性中清除任何本地應用的值提供了一個接口。但是,調用 ClearValue 并不能保證注冊屬性時在元數據中指定的默認值就是新的有效值。值優先級中的所有其他參與者仍然有效。只有在本地設置的值才會從優先級序列中移除。例如,如果您對同時也由主題樣式設置的屬性調用 ClearValue,主題值將作為新值而不是基于元數據的默認值進行應用。如果您希望取消過程中的所有屬性值,而將值設置為注冊的元數據默認值,則可以通過查詢依賴項屬性的元數據來最終獲得默認值,然后使用該默認值在本地設置屬性并調用 SetValue來實現,這里我們得感得PropertyMetadata類為我們提供了諸如DefaultValue這樣的外部可訪問的屬性。

上面講了這么多,現在我們就簡單用一個例子來說明上面的原理(例子很直觀,相信大家能很容易看懂)

XAML中代碼如下:

<Window x:Class="WpfApplication1.DPClearValue"
xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="//schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="400" Width="400">
<StackPanel Name="root">
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="250"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
<Style TargetType="Ellipse">
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="50"/>
<Setter Property="Fill" Value="LightBlue"/>
</Style>
<Style TargetType="Rectangle">
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="50"/>
<Setter Property="Fill" Value="MediumBlue"/>
</Style>
<Style x:Key="ShapeStyle" TargetType="Shape">
<Setter Property="Fill" Value="Azure"/>
</Style>
</StackPanel.Resources>
<DockPanel Name="myDockPanel">
<Ellipse Height="100" Width="100" Style="{StaticResource ShapeStyle}"/>
<Rectangle Height="100" Width="100" Style="{StaticResource ShapeStyle}" />
</DockPanel>
<Button Name="RedButton" Click="MakeEverythingAzure" Height="39" Width="193">改變所有的值</Button>
<Button Name="ClearButton" Click="RestoreDefaultProperties" Height="34" Width="192"> 清除本地值</Button>
</StackPanel>
</Window>
 

后臺代碼:

public partial class DPClearValue
{
//清除本地值,還原到默認值
void RestoreDefaultProperties(object sender, RoutedEventArgs e)
{
UIElementCollection uic = myDockPanel.Children;
foreach (Shape uie in uic)
{
LocalValueEnumerator locallySetProperties = uie.GetLocalValueEnumerator();
while (locallySetProperties.MoveNext())
{
DependencyProperty propertyToClear = (DependencyProperty)locallySetProperties.Current.Property;
if (!propertyToClear.ReadOnly) { uie.ClearValue(propertyToClear); }
}
}
}

//修改本地值
void MakeEverythingAzure(object sender, RoutedEventArgs e)
{
UIElementCollection uic = myDockPanel.Children;
foreach (Shape uie in uic) { uie.Fill = new SolidColorBrush(Colors.Azure); }
}
}

當按下&rdquo;改變所有的值“按鈕的時候,就會把之前的值都進行修改了,這個時候按下”清除本地值“就會使原來的所有默認值生效。

 

十一. 依賴屬性元數據

前面我們看到一個依賴屬性的注冊最全的形式是下面這樣子的:

public static DependencyProperty Register(string name,
Type propertyType,
Type ownerType,
PropertyMetadata typeMetadata,
ValidateValueCallback validateValueCallback);

  第一個參數是該依賴屬性的名字,第二個參數是依賴屬性的類型,第三個參數是該依賴屬性的所有者的類型,第五個參數就是一個驗證值的回調委托,那么最使我們感興趣的還是這個可愛的 PropertyMetadata ,也就是我們接下來要講的元數據。 提到WPF屬性元數據,大家可能第一想到的是剛才的PropertyMetadata,那么這個類到底是怎樣的呢?我們應該怎樣使用它呢?首先我們看它的構造函數(我們選參數最多的來講):

public PropertyMetadata(object defaultValue,
PropertyChangedCallback propertyChangedCallback,
CoerceValueCallback coerceValueCallback);

  其中的第一個參數是默認值,最后兩個分別是PropertyChanged(變化通知)以及Coerce(強制)的兩個委托變量,我們在實例化的時候,只需要把這兩個委托變量關聯到具體的方法上即可。

  事實上,除了PropertyMetadata以外,常見的還有FrameworkPropertyMetadata,UIPropertyMetadata。他們的繼承關系是F->U-&gt;P。其中以FrameworkPropertyMetadata參數最多,亦最為復雜。

  FrameworkPropertyMetadata的構造函數提供了很多重載,我們挑選最為復雜的重載來看它到底有哪些參數以及提供了哪些功能:

public FrameworkPropertyMetadata(object defaultValue,
FrameworkPropertyMetadataOptions flags,
PropertyChangedCallback propertyChangedCallback,
CoerceValueCallback coerceValueCallback,
bool isAnimationProhibited,
 UpdateSourceTrigger defaultUpdateSourceTrigger);

  其中第一個參數是默認值,最后兩個參數分別是是否允許動畫,以及綁定時更新的策略(在Binding當中相信大家并不陌生),這個不詳細解釋了。重點看一下里第三、四兩個參數,兩個 CallBack的委托。結合前面Register的時候提到的ValidateValueCallback共組成三大&rdquo;金剛“,這三個Callback分別代表Validate(驗證),PropertyChanged(變化通知)以及Coerce(強制)。當然,作為 Metadata,FrameworkPropertyMetadata只是儲存了該依賴屬性的策略信息,WPF屬性系統會根據這些信息來提供功能并在適當的時機回調傳入的delegate,所以最重要的還是我們定義的這些方法,通過他們傳入委托才能起到真正的作用。

  上面講了元數據暴露給我們的構造函數,其實在其內部還提供了兩個方法,這個在做自定義控件的時候,也很值得注意:

protected virtual void Merge(PropertyMetadata baseMetadata, DependencyProperty dp)
{
// 實現元數據繼承之間的合并
}

protected virtual void OnApply(DependencyProperty dependencyProperty, Type targetType)
{
// 當元數據被這個屬性應用,OnApply就會被觸發,在此時元數據也將被密封起來。
}

前面講了這么多,那么我們現在就來看看依賴屬性回調、驗證及強制值到底是怎么使用的呢?大家千萬要堅持住,后面內容更加精彩!

十二. 依賴屬性回調、驗證及強制值

我們通過下面的這幅圖,簡單介紹一下WPF屬性系統對依賴屬性操作的基本步驟:

 

  • 第一步,基礎值就是上面“六.依賴屬性的優先級”提供的那些顯示設置,所以它的優先級比較好確定,但有些不會按常規出牌,所以也需要注意總結。
  • 第二步,如果依賴屬性值是計算表達式 (如前面示例中的綁定等語法特性),這個時候就會計算表達式的結果作為第二步的值。
  • 第三步,動畫是一種優先級很高的特殊行為,很多時候,我們都會聽到動畫優先的聲音,所以它的優先級高于其他基礎設置;
  • 第四步,強制則是注冊時提供的 CoerceValueCallback 委托,它負責驗證屬性值是否在允許的限制范圍之內,和我們對屬性的驗證一樣,比如強制設置該值必須大于于0小于10等等;
  • 第五步,驗證是指我們注冊依賴屬性所提供的 ValidateValueCallback 委托方法,它最終決定了屬性值設置是否有效,當數據無效時會拋出異常來通知。

前面我們講了基本的流程,下面我們就用一個小的例子來進行說明:

namespace SampleProcess_DPs
{
class Program
{
static void Main(string[] args)
{
SimpleDPClass sDPClass = new SimpleDPClass();
sDPClass.SimpleDP = 8;
Console.ReadLine();
}
}

public class SimpleDPClass : DependencyObject
{
public static readonly DependencyProperty SimpleDPProperty =
DependencyProperty.Register("SimpleDP", typeof(double), typeof(SimpleDPClass),
new FrameworkPropertyMetadata((double)0.0,
FrameworkPropertyMetadataOptions.None,
new PropertyChangedCallback(OnValueChanged),
new CoerceValueCallback(CoerceValue)),
new ValidateValueCallback(IsValidValue));

public double SimpleDP
{
get { return (double)GetValue(SimpleDPProperty); }
set { SetValue(SimpleDPProperty, value); }
}

private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Console.WriteLine("當值改變時,我們可以做的一些操作,具體可以在這里定義: {0}", e.NewValue);
}

private static object CoerceValue(DependencyObject d, object value)
{
Console.WriteLine("對值進行限定,強制值: {0}", value);
return value;
}

private static bool IsValidValue(object value)
{
Console.WriteLine("驗證值是否通過,返回bool值,如果返回True表示嚴重通過,否則會以異常的形式暴露: {0}", value);
return true;
}

}
}

 

結果如下:

 

  當SimpleDP屬性變化之后,PropertyChangeCallback就會被調用。可以看到結果并沒有完全按照我們先前的流程先Coerce后Validate的順序執行,有可能是WPF內部做了什么特殊處理,當屬性被修改時,首先會調用Validate來判斷傳入的value是否有效,如果無效就不繼續后續的操作,這樣可以更好的優化性能。從上面的結果上看出,CoerceValue后面并沒有立即ValidateValue,而是直接調用了PropertyChanged。這是因為前面已經驗證過了value,如果在Coerce中沒有改變value,那么就不用再驗證了。如果在 Coerce中改變了value,那么這里還會再次調用ValidateValue操作,和前面的流程圖執行的順序一樣,在最后我們會調用ValidateValue來進行最后的驗證,這就保證最后的結果是我們希望的那樣了(正如打游戲一樣,打了小怪,在最后過總關的時候還是需要打大怪才能闖關的)。

  上面簡單介紹了處理流程,下面我們就以一個案例來具體看一看上面的流程到底有沒有出入,這個例子改編于Sacha Barber 的Dependency Properties代碼示例,我相信通過這段代碼你會對這個上面講的概念有更清晰地認識。

  UI很簡單,黃色部分顯示當前值,我們在初始化的時候把它設置為100,然后它的最小值和最大值分別設置為0和500,按鈕”設置為-100“企圖把當前值設為-100,按鈕”設置為1000“試圖把當前值設為1000。具體大家看代碼(我都寫了注釋,很容易理解的).

 

依賴屬性代碼文件如下:

namespace Callback_Validation_DPs
{
public class Gauge : Control
{
public Gauge() : base() { }
//注冊CurrentReading依賴屬性,并添加PropertyChanged、CoerceValue、ValidateValue的回調委托
public static readonly DependencyProperty CurrentReadingProperty = DependencyProperty.Register(
"CurrentReading",
typeof(double),
typeof(Gauge),
new FrameworkPropertyMetadata(
Double.NaN,
FrameworkPropertyMetadataOptions.None,
new PropertyChangedCallback(OnCurrentReadingChanged),
new CoerceValueCallback(CoerceCurrentReading)
),
new ValidateValueCallback(IsValidReading)
);

//屬性包裝器,通過它來暴露CurrentReading的值
public double CurrentReading
{
get { return (double)GetValue(CurrentReadingProperty); }
set { SetValue(CurrentReadingProperty, value); }
}

//注冊MinReading依賴屬性,并添加PropertyChanged、CoerceValue、ValidateValue的回調委托
public static readonly DependencyProperty MinReadingProperty = DependencyProperty.Register(
"MinReading",
typeof(double),
typeof(Gauge),
new FrameworkPropertyMetadata(
double.NaN,
FrameworkPropertyMetadataOptions.None,
new PropertyChangedCallback(OnMinReadingChanged),
new CoerceValueCallback(CoerceMinReading)
),
new ValidateValueCallback(IsValidReading));

//屬性包裝器,通過它來暴露MinReading的值
public double MinReading
{
get { return (double)GetValue(MinReadingProperty); }
set { SetValue(MinReadingProperty, value); }
}

//注冊MaxReading依賴屬性,并添加PropertyChanged、CoerceValue、ValidateValue的回調委托
public static readonly DependencyProperty MaxReadingProperty = DependencyProperty.Register(
"MaxReading",
typeof(double),
typeof(Gauge),
new FrameworkPropertyMetadata(
double.NaN,
FrameworkPropertyMetadataOptions.None,
new PropertyChangedCallback(OnMaxReadingChanged),
new CoerceValueCallback(CoerceMaxReading)
),
new ValidateValueCallback(IsValidReading)
);

//屬性包裝器,通過它來暴露MaxReading的值
public double MaxReading
{
get { return (double)GetValue(MaxReadingProperty); }
set { SetValue(MaxReadingProperty, value); }
}

//在CoerceCurrentReading加入強制判斷賦值
private static object CoerceCurrentReading(DependencyObject d, object value)
{
Gauge g = (Gauge)d;
double current = (double)value;
if (current < g.MinReading) current = g.MinReading;
if (current > g.MaxReading) current = g.MaxReading;
return current;
}


//當CurrentReading值改變的時候,調用MinReading和MaxReading的CoerceValue回調委托
private static void OnCurrentReadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.CoerceValue(MinReadingProperty);
d.CoerceValue(MaxReadingProperty);
}

//當OnMinReading值改變的時候,調用CurrentReading和MaxReading的CoerceValue回調委托
private static void OnMinReadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.CoerceValue(MaxReadingProperty);
d.CoerceValue(CurrentReadingProperty);
}

//在CoerceMinReading加入強制判斷賦值
private static object CoerceMinReading(DependencyObject d, object value)
{
Gauge g = (Gauge)d;
double min = (double)value;
if (min > g.MaxReading) min = g.MaxReading;
return min;
}

//在CoerceMaxReading加入強制判斷賦值
private static object CoerceMaxReading(DependencyObject d, object value)
{
Gauge g = (Gauge)d;
double max = (double)value;
if (max < g.MinReading) max = g.MinReading;
return max;
}

//當MaxReading值改變的時候,調用MinReading和CurrentReading的CoerceValue回調委托
private static void OnMaxReadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.CoerceValue(MinReadingProperty);
d.CoerceValue(CurrentReadingProperty);
}

//驗證value是否有效,如果返回True表示驗證通過,否則會提示異常
public static bool IsValidReading(object value)
{
Double v = (Double)value;
return (!v.Equals(Double.NegativeInfinity) && !v.Equals(Double.PositiveInfinity));
}
}
}

 

XAML代碼如下:

<Window x:Class="Callback_Validation_DPs.Window1"
xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="//schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Callback_Validation_DPs"
WindowStartupLocation="CenterScreen"
Title="Callback_Validation_DPs" Height="400" Width="400">
<StackPanel Orientation="Vertical">
<local:Gauge x:Name="gauge1" MaxReading="100" MinReading="0" />
<Label Content="可以設置最小值為0和最小大值為500" Height="30"/>
<StackPanel Orientation="Horizontal" Height="60">
<Label Content="當前值為 : "/>
<Label Background="Yellow" BorderBrush="Black" BorderThickness="1"
IsEnabled="False" Content="{Binding ElementName=gauge1, Path=CurrentReading}" Height="25" VerticalAlignment="Top" />
</StackPanel>
<Button x:Name="btnSetBelowMin" Content="設置為 -100"
Click="btnSetBelowMin_Click"/>
<Button x:Name="btnSetAboveMax" Content="設置為 1000"
Click="btnSetAboveMax_Click"/>
</StackPanel>
</Window>
 

XAML的后臺代碼如下:

public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
//設置CurrentReading的值,這個時候會觸發哪些變化?調試代碼吧!
gauge1.CurrentReading = 100;
}

private void btnSetBelowMin_Click(object sender, RoutedEventArgs e)
{
//設置CurrentReading的值,這個時候會觸發哪些變化?調試代碼吧!
gauge1.CurrentReading = -100;
}

private void btnSetAboveMax_Click(object sender, RoutedEventArgs e)
{
//設置CurrentReading的值,這個時候會觸發哪些變化?調試代碼吧!
gauge1.CurrentReading = 10000;

}
}

  在上面的例子中,一共有三個依賴屬性相互作用——CurrentReading、MinReading和MaxReading,這些屬性相互作用,但它們的規則是MinReading≤CurrentReading≤MaxReading。根據這個規則,當其中一個依賴屬性變化時,另外兩個依賴屬性必須進行適當的調整,這里我們要用到的就是CoerceValue這個回調委托,那么實現起來也非常的簡單,注冊MaxReading的時候加入CoerceValueCallback,在CoerceMaxReading函數中做處理:如果Maximum的值小于MinReading,則使MaxReading值等于MinReading;同理在CurrentReading中也加入了CoerceValueCallback進行相應的強制處理。然后在MinReading的ChangedValueCallback被調用的時候,調用CurrentReading和MaxReading的CoerceValue回調委托,這樣就可以達到相互作用的依賴屬性一變應萬變的”千機變“。

  換句話說,當相互作用的幾個依賴屬性其中一個發生變化時,在它的PropertyChangeCallback中調用受它影響的依賴屬性的CoerceValue,這樣才能保證相互作用關系的正確性。 前面也提高ValidateValue主要是驗證該數據的有效性,最設置了值以后都會調用它來進行驗證,如果驗證不成功,則拋出異常。

十三. 依賴屬性監聽

  如果想監聽依賴屬性的改變,可以用兩種方法實現,在很多時候,我們兩種方法都會用到:
  用DependencyPropertyDescriptor 比較簡便,在代碼里面寫起來也比較便捷;
  用OverrideMetadata的方式主要在自定義控件以及處理一些類間關系的時候;
  第一種方法:派生自這個類,然后定義它的屬性,重寫屬性的原數據并傳遞一個PropertyChangedCallBack參數即可,如下代碼:

public class MyTextBox : TextBox
{
public MyTextBox(): base()
{
}

static MyTextBox()
{
//第一種方法,通過OverrideMetadata
FlowDirectionProperty.OverrideMetadata(typeof(MyTextBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(FlowDirectionPropertyChanged)));
}

private static void FlowDirectionPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
((MyTextBox)sender).FontWeight = (((MyTextBox)sender).FlowDirection == FlowDirection.LeftToRight) ? FontWeights.Bold : FontWeights.Normal;

}
}

 

第二種方法:這個方法更加簡單,獲取DependencyPropertyDescriptor并調用AddValueChange()為其掛接一個回調函數,如下代碼:

private void Window1_Loaded(object sender, RoutedEventArgs e)
{
//第二種方法,通過OverrideMetadata
DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor.FromProperty(TextBox.TextProperty, typeof(TextBox));
descriptor.AddValueChanged(tbxEditMe, tbxEditMe_TextChanged);
}

private void tbxEditMe_TextChanged(object sender, EventArgs e)
{
MessageBox.Show("", "Changed");
}

十四. 代碼段(自動生成)

  代碼段可以說是一個非常普遍且實用的功能,我們可以利用它來簡化和規范我們的代碼。在項目當中我們通常會定義大量的代碼段,如怎樣寫一個類、怎樣定義一個方法、公用代碼庫等等都可以定義成代碼段,今天不著重講這一塊,下面就來看看在默認的VS中有哪些代碼段

 

  上面看到的是visual basic的代碼段(一不小心截圖截錯了,呵呵),但不幸的是針對C#的代碼段卻很少。不過沒關系,既然默認沒有提供那么多代碼段,我們可以自己動手嘛,正所謂自己動手豐衣足食嘛!相信大家都有自定義代碼段的經歷,同時在網上也有很多好的代碼段下載,我用得最多的是DrWPFSnippets,由于接觸WPF和Silverlight是在07年,所以當時自己也定義過一些代碼段,由于自己主要精力還是在技術架構、ASP.NET、WCF、OO等方面,所以在08年以后就開始使用網上的代碼段資源了,當然由于之前項目也自己寫了一些代碼段,所以很多時候都是混合起來使用,大家可以到去下載,這個代碼段包最早從2007年11月就提供下載了,在今年四月份進行了升級,同時支持VS2005/VS2008/VS2010,所以大家可以下載下來體驗一下,很不錯的哦!下載以后點擊DrWPFSnippets.vsi就會自動安裝,安裝完成以后,你會看到如下界面,圖中的Shortcut就是你要按的快捷鍵,不過生成的代碼會出現有些幫助類找不到的情況,如RoutedEvent會生成一個RoutedEventHelper的類,這個是沒有關系的,你到網上一搜就可以把這個類加入到你的代碼當中。那么運行就十分正常了。在安裝的時候提醒一下,最好一次安裝成功,否則你會為眾多的彈窗口感到十分厭惡,呵呵!

 

那么現在你就可以在項目當中使用了,如按下re+TAB鍵兩次,你就會看到如下界面,然后選擇你的選項即可生成需要的代碼(這里re就是Routed event的簡寫)。

 

如下是生成的代碼,你可以直接使用或者經過適當修改使用。

#region Swindle

/// <summary>
/// Swindle Routed Event
/// </summary>
public static readonly RoutedEvent SwindleEvent = EventManager.RegisterRoutedEvent("Swindle",
RoutingStrategy.Bubble, typeof(TrioEventHandler), typeof(Window1));

/// <summary>
/// Occurs when ...
/// </summary>
public event TrioEventHandler Swindle

{
add { AddHandler(SwindleEvent, value); }
remove { RemoveHandler(SwindleEvent, value); }
}

/// <summary>
/// A helper method to raise the Swindle event.
/// </summary>
/// <param name="arg"> </param>
/// <param name="arg2"> </param>
/// <param name="arg3"> </param>
protected TrioEventArgs RaiseSwindleEvent(bool arg, bool arg2, bool arg3)
{
return RaiseSwindleEvent(this, arg, arg2, arg3);
}

/// <summary>
/// A static helper method to raise the Swindle event on a target element.
/// </summary>
/// <param name="target">UIElement or ContentElement on which to raise the event</param>
/// <param name="arg"> </param>
/// <param name="arg2"> </param>
/// <param name="arg3"> </param>
internal static TrioEventArgs RaiseSwindleEvent(DependencyObject target, bool arg, bool arg2, bool arg3)
{
if (target == null) return null;

TrioEventArgs args = new TrioEventArgs(arg, arg2, arg3);
args.RoutedEvent = SwindleEvent;
RoutedEventHelper.RaiseEvent(target, args);
return args;
}

#endregion

十五. 模擬依賴屬性實現

  古人有”不入虎穴焉得虎子“的名句,我們今天也試著入一入虎穴,探探依賴屬性里面到底藏著什么不可告人的秘密,在往下講之前,我們先來看一下DependencyObject 、DependencyProperty 以及PropertyMetadata到底包含哪些功能,如下面三幅圖

 

 

 

 

   

  通過前面三幅圖,我們就可以了解WPF依賴屬性系統的大體結構以及主要功能,再者通過前面我們對它的使用,對它的內部實現也有一個相對比較清晰的認識,那么接下來要做的就是:借助Reflector+VS調試內部代碼功能一起來研究其內部的實現原理。 本來想詳細寫清楚開發的過程,但是有點多,所以我打算直接講這幾個類。大家也可以通過這個思路來試一試,同時還可以參考Mono的源碼、WF的依賴屬性源碼等。這里要推薦的是周永恒的博客,此人對技術的理解很是透徹,博文雖少,但每篇都堪稱經典,所以他的文章,我都通讀三遍。雖然大多概念都懂,并且讀到深處也能產生共鳴,其最主要目的還是學習他這種”闡述問題的思路“,后來也和此人MSN聊過幾次。所以這個依賴屬性的框架在某些程度上也借鑒了他的一些寫法。

  有了前面的思路,首先定義DependencyProperty這個類,它里面存儲前面我們提到希望抽出來的字段。DependencyProperty內部維護了一個全局的Map用來儲存所有的DependencyProperty,對外暴露了一個Register方法用來注冊新的DependencyProperty。當然,為了保證在Map中鍵值唯一,注冊時需要根據傳入的名字和注冊類的的 HashCode取異或來生成Key。 所以我們就可以完成DependencyProperty類了,代碼如下,介紹詳見代碼注釋。:

public sealed class DependencyProperty
{
//全局的IDictionary用來儲存所有的DependencyProperty
internal static IDictionary<int, DependencyProperty> properties = new Dictionary<int, DependencyProperty>();
//存儲元數據的集合
private List<PropertyMetadata> _metadataMap = new List<PropertyMetadata>();
private static int globalIndex = 0;
private PropertyMetadata def_metadata;
private bool attached;
private string name;
private int _index;
private Type owner_type;
private Type property_type;
private Type validator_type;

// 構造函數
private DependencyProperty()
{

}

//構造函數私有,保證外界不會對它進行實例化
private DependencyProperty(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
{
this.name = name;
property_type = propertyType;
owner_type = ownerType;
def_metadata = defaultMetadata;
}

// 常用屬性
public PropertyMetadata DefaultMetadata
{
get { return def_metadata; }
}

public bool IsAttached
{
get { return attached; }
}

public int Index
{
get { return _index; }
set { _index = value; }
}

public string Name
{
get { return name; }
}

public Type OwnerType
{
get { return owner_type; }
}

public Type PropertyType
{
get { return property_type; }
}

public Type ValidatorType
{
get { return validator_type; }
}


public override int GetHashCode()
{
return name.GetHashCode() ^ owner_type.GetHashCode();
}

//注冊依賴屬性
public static DependencyProperty Register(string name, Type propertyType, Type ownerType)
{
return Register(name, propertyType, ownerType, new PropertyMetadata());
}

//注冊的公用方法,把這個依賴屬性加入到IDictionary的鍵值集合中,Key為name和owner_type的GetHashCode取異,Value就是我們注冊的DependencyProperty
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
{
DependencyProperty property = new DependencyProperty(name, propertyType, ownerType, defaultMetadata);
globalIndex++;
property.Index = globalIndex;

if (properties.ContainsKey(property.GetHashCode()))
{
throw new InvalidOperationException("A property with the same name already exists");
}

//把剛實例化的DependencyProperty添加到這個全局的IDictionary種
properties.Add(property.GetHashCode(), property);
return property;
}

//注冊只讀依賴屬性
public static DependencyProperty RegisterReadOnly(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
{
DependencyProperty property = Register(name, propertyType, ownerType, typeMetadata);
return property;
}

//注冊附加依賴屬性
public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType)
{
return RegisterAttached(name, propertyType, ownerType, new PropertyMetadata(), null);
}

public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
{
return RegisterAttached(name, propertyType, ownerType, defaultMetadata, null);
}

public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, Type validatorType)
{
DependencyProperty property = Register(name, propertyType, ownerType, defaultMetadata);
property.attached = true;
property.validator_type = validatorType;
return property;
}

//子類繼承重寫以及其他需要重寫Metadata的時候使用
public void OverrideMetadata(Type forType, PropertyMetadata metadata)
{
metadata.Type = forType;
_metadataMap.Add(metadata);
}

//獲取元數據信息
public PropertyMetadata GetMetadata(Type type)
{
PropertyMetadata medatata = _metadataMap.FirstOrDefault((i) => i.Type == type) ??
_metadataMap.FirstOrDefault((i) => type.IsSubclassOf(i.Type));
if (medatata == null)
{
medatata = def_metadata;
}
return medatata;
}

}

  有了DependencyProperty ,那么接下來就需要定義DependencyObject 來使用這個DependencyProperty 。首先使用DependencyProperty .Register方法注冊了一個新的DependencyProperty ,然后提供了GetValue和SetValue兩個方法來操作剛剛構造的DependencyProperty 。這個時候我們看到一個簡單的依賴屬性系統已初見端倪了,詳見代碼注釋。

namespace Realize_DPs
{
public abstract class DependencyObject : IDisposable
{
//添加一個List來記錄修改信息
private List<EffectiveValueEntry> _effectiveValues = new List<EffectiveValueEntry>();

//屬性包裝器,通過它來訪問依賴屬性
public object GetValue(DependencyProperty dp)
{
//首先通過判斷是否改動過,以此來決定是讀元數據的默認值還是改動了的值
EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault((i) => i.PropertyIndex == dp.Index);
if (effectiveValue.PropertyIndex != 0)
{
return effectiveValue.Value;
}
else
{
PropertyMetadata metadata;
metadata = DependencyProperty.properties[dp.GetHashCode()].DefaultMetadata;
return metadata.DefaultValue;
}
}

//屬性包裝器,通過它來設置依賴屬性的值
public void SetValue(DependencyProperty dp, object value)
{
//首先通過判斷是否改動過,以及改動過,則繼續對改動過的元素賦值,否則對_effectiveValues增加元素
EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault((i) => i.PropertyIndex == dp.Index);
if (effectiveValue.PropertyIndex != 0)
{
effectiveValue.Value = value;
}
else
{
effectiveValue = new EffectiveValueEntry() { PropertyIndex = dp.Index, Value = value };
_effectiveValues.Add(effectiveValue);
}
}

public void Dispose()
{
//暫時還沒有處理
}
}

internal struct EffectiveValueEntry
{
internal int PropertyIndex { get; set; }
internal object Value { get; set; }
}
}

  前面有了DependencyProperty 和DependencyObject 類,那我們現在來新建一個比較重要的類 PropertyMetadata ,它的作用和功能很強大,我們這里只是簡單進行了構建,如下代碼:

namespace Realize_DPs
{
public delegate void SetValueOverride(DependencyObject d, object value);

public delegate object GetValueOverride(DependencyObject d);

public class PropertyMetadata
{
private object default_value;
private DependencyPropertyOptions options = DependencyPropertyOptions.Default;
private bool _sealed = false;
private SetValueOverride set_value;
private GetValueOverride get_value;
private Attribute[] attributes;
private Type type;

// 構造函數重載
public PropertyMetadata()
{

}

public PropertyMetadata(object defaultValue)
{
default_value = defaultValue;
}

public PropertyMetadata(DependencyPropertyOptions options)
{
this.options = options;
}

public PropertyMetadata(params Attribute[] attributes)
{
this.attributes = attributes;
}

public PropertyMetadata(object defaultValue, params Attribute[] attributes)
{
default_value = defaultValue;
this.attributes = attributes;
}

public PropertyMetadata(object defaultValue, DependencyPropertyOptions options)
{
default_value = defaultValue;
this.options = options;
}

public PropertyMetadata(DependencyPropertyOptions options, params Attribute[] attributes)
{
this.options = options;
this.attributes = attributes;
}

public PropertyMetadata(object defaultValue, DependencyPropertyOptions options, params Attribute[] attributes)
{
this.options = options;
default_value = defaultValue;
this.attributes = attributes;
}

public PropertyMetadata(object defaultValue, DependencyPropertyOptions options, GetValueOverride getValueOverride, SetValueOverride setValueOverride)
{
this.options = options;
default_value = defaultValue;
set_value = setValueOverride;
get_value = getValueOverride;
}

public PropertyMetadata(object defaultValue, DependencyPropertyOptions options, GetValueOverride getValueOverride, SetValueOverride setValueOverride, params Attribute[] attributes)
{
this.options = options;
default_value = defaultValue;
set_value = setValueOverride;
get_value = getValueOverride;
this.attributes = attributes;
}

// 常用屬性
public object DefaultValue
{
get { return default_value; }
set { default_value = value; }
}

public GetValueOverride GetValueOverride
{
get { return get_value; }
set { get_value = value; }
}

public bool IsMetaProperty
{
get { return (options & DependencyPropertyOptions.Metadata) == DependencyPropertyOptions.Metadata; }
}

public bool IsNonSerialized
{
get { return (options & DependencyPropertyOptions.NonSerialized) == DependencyPropertyOptions.NonSerialized; }
}

public bool IsReadOnly
{
get { return (options & DependencyPropertyOptions.Readonly) == DependencyPropertyOptions.Readonly; }
}

protected bool IsSealed
{
get { return _sealed; }
}

public DependencyPropertyOptions Options
{
get { return options; }
set { options = value; }
}

public SetValueOverride SetValueOverride
{
get { return set_value; }
set { set_value = value; }
}

public Type Type
{
get { return type; }
set { type = value; }
}

protected virtual void Merge(PropertyMetadata baseMetadata, DependencyProperty dp)
{
// 實現元數據繼承之間的合并
}

protected virtual void OnApply(DependencyProperty dependencyProperty, Type targetType)
{
// 當元數據被這個屬性應用,OnApply就會被觸發,在此時元數據也將被密封起來。
}
}
}

前面我們實現了一個簡單的依賴屬性系統,現在就得先測試一下其功能,代碼如下:

class Program : DependencyObject
{
public static readonly DependencyProperty CounterProperty;
static Program()
{
//注冊依賴屬性Counter
CounterProperty = DependencyProperty.Register("Counter",
typeof(double),
typeof(Program),
new PropertyMetadata(8.0));
}

//屬性包裝器,暴露讀寫接口
public double Counter
{
get { return (double)GetValue(CounterProperty); }
set {SetValue(CounterProperty, value); }
}

static void Main(string[] args)
{
Program pro = new Program();
Console.WriteLine("讀取元數據設置的默認值: "+pro.Counter.ToString());

Program pro2 = new Program();
pro2.Counter = 22.5;
Console.WriteLine("通過SetValue設置改變了的值: " + pro2.Counter.ToString());
Console.ReadLine();
}
}

那么測試結果為:

 

利用VS自帶的類圖,可以看到剛才我們實現的這個依賴屬性類及類之間的關系圖:

 

十六. 本文總結

  這篇文章洋洋灑灑寫了很多,我們現在簡單回顧一下:在開篇之前我們會先介紹比本篇更重要的一些東西,然后插播了一段”云計算之旅“的廣告(廣告費很昂貴 ,所以格外小心),作為最近幾個月執著研究的東西,終于可以在下周和大家見面了,所以心中甚是喜悅。在前面的兩個內容之后我們正式進入本篇的主題——依賴屬性。依賴屬性是WPF的核心概念,所以我們花費了大量的時間和篇幅進行論述,首先從依賴屬性基本介紹講起,然后過渡到依賴屬性的優先級、附加屬性、只讀依賴屬性、依賴屬性元數據、依賴屬性回調、驗證及強制值、依賴屬性監聽、代碼段(自動生成) 等相關知識,最后我們模擬了一個WPF依賴屬性的實現,對內部實現原理進行了一些研究。在接下來的三篇”剖析路由事件”、”剖析命令”、”剖析綁定”也會采用這篇文章的風格,希望能盡量說透,如果有誤之處還希望各位能夠批評指正!

十七. 相關代碼下載

  在文章的最后,我們提供代碼的下載,這幾篇文章最重要的就是下載代碼來細細研究,代碼里面也添加了比較詳細的注釋,如果大家有什么問題,也可以和我聯系,如果有不正確的地方也希望多多海涵并能給我及時反饋,我將感激不盡!


標簽:

本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn

文章轉載自:博客轉載自圣殿騎士

為你推薦

  • 推薦視頻
  • 推薦活動
  • 推薦產品
  • 推薦文章
  • 慧都慧問
掃碼咨詢


添加微信 立即咨詢

電話咨詢

客服熱線
023-68661681

TOP
主站蜘蛛池模板: 日韩欧美中文一区 | 青青操女人| 日韩精品推荐 | 国产免费区 | 成人精品性色一二三区 | 日韩在线欧美高清一区 | www东京热| 国产高潮久久 | 韩国成人网站 | heyzo综合高清| 国产成人久久久 | 国产精品福利影院 | 黄色三在线 | 三级毛片视频 | 三级黄色免费网站 | 日韩免费高清大片在线 | 操逼网首页123 | 成人免费片 | 午夜福利无码在线 | 操孕妇无码视频 | 国产在线无码一区 | 日韩亚洲欧美在线观看 | 国产熟妇勾子乱 | 日韩区欧美国产区在线 | 国产二区视频 | 日韩素人一区二区 | 国产二级片 | 日韩欧美视频免费观看 | 91网站观看| 成人性爱在线视频 | 成人毛片A级 | 午夜成人影视频道 | 中文综合久久 | 国产呦精品 | 午夜视频啪日本 | 成人激情视频在线观看 | 成人三级在线视频 | 成人小视频在线 | 伦利理午夜理论片 | 成人短片| 日韩中文字暮精品 | 99导航| 国产白丝在线观看 | 成人午夜激情影院 | 国产成色在线 | 日韩精品一区二区三 | 成人无码区免费AⅤ | 日韩欧美一区二区丁香 | 日韩欧美美女综合 | 97福利影视| 国产97swa| 女人脱精光按摩AA片 | 日韩中文精品 | 久久综合888 | 成人午夜在线免费 | 国产自拍91 | 国产大片一区 | 免费毛片a | 白丝一区二区 | 国产AⅤ无码 | 麻豆精品在线 | 91丨露脸丨熟女抽搐 | 少妇导航 | 国産精品久久久久久久 | 午夜成人精品在线 | 老司机69| 日韩国产免费 | 国产主播福利在线 | 日韩国产在线 | 九一果冻制作厂余丽 | 午夜成人 | 蜜臀91久久国产人妻 | 福利视频导航在线观看 | 激情文学视频在线 | 精东黄色传媒视频 | 日韩狼友| 成人日韩精品在线 | 日韩性爱在线观看 | 深夜福利不卡 | 高潮视频在线观看 | 日韩欧美三级在线 | 国产精品青草久 | 韩国三级久久 | 日韩亚洲欧美精品综合 | 精品处破女学生 | 玖玖亚洲电影 | 日韩成人专区 | 日韩在线高清视频 | 成人福利导航大全在线 | 久草资源站| 国产色三线免费 | 精品有码| 天美免费在线传煤mv | 91视频www| 国产无套内射视频 | 国产亚洲不卡 | 午夜福利网午夜福利网 | 国产91丝袜在线熟女 | 亚洲国产成人aⅴ | 国产a网 | 97就去色 | 日韩v在线 | 成人免费软件 | 91巨炮在线| 国产黄大全 | 九九九九色 | 东京99热这里精品 | 日韩欧美精品视频在线 | 亚洲国产网站在线观看 | 真实国产亂伦十页 | 一A级成人免费版 | 久久骚妇| 五月花网站 | 三级在线国产 | 成人动漫一区二区 | 涩涩。com| 成人深夜在线观看 | 国产黄色在线免费观看 | 成人欧美视频 | 日韩一区二精品成人免 | 婷婷午夜影院 | 激情小说网址 | 日韩淫水 | 簧片在线免费观看 | 97超碰成人 | 蜜臀TV一区 | 国产人免费视频 | 黄色美女视频 | 国产精品乱视频 | 国产主播网 | 午夜伦理三级 | 成人天堂| 日韩精品免费一级视频 | 丁香五月天婷婷综合 | 午夜AV在线 | 国产原创视频在线 | 国产岛片在线观看 | 国产l精品国产亚洲 | 激情文学网址 | 日韩高清电影网 | 欧美视频一区 | 玖玖在线 | 日韩精品一页 | 91桃色一| 午夜福利成人视频 | 国产第一网站 | 午夜免费影视 | 日韩第9页| 超碰人人91| 日本人妻乱码 | 午夜福利在线导航 | 成人免费观看三级片 | 日本草莓视频在线观看 | 加勒比一区二区 | 成人福利在线视频 | 国产大片视频免费观看 | 强奸乱伦一区 | 激情小说图片在线视频 | 日韩五码 | 成人深夜精品 | 真实国产亂伦在线视频 | 91视色| 欧美精品一区二 | 国产精品美女在线观看 | 屁屁影院第二页 | 天天干天天操 | 国产精品三级片 | 成人h在线观看 | 在线免费一区二区视频 | 又黄又刺激的视频 | 国产成人精品AV片 | 日韩午夜免费电影 | 日韩欧美一级性视频 | 国产xx00视频在 | 国产情侣在视频 | 久久精品视频2025 | 日韩和的一区二在线 | A级成人毛片免费网站 | 成人抖音视频 | 日韩美女诱惑 | 在线激情网 | 国产无套内射视频 | 国产又爽又黄免费软件 | 午夜日韩视频0 | 日韩美女成人免费网站 | 国产精品女主播 | 国产白丝精品 | 亚洲国产精品电影 | 成人精品电影一 | 岛国高清无码 | 97人人操人人看 | 日韩精品高清第一区 | 三级天堂网| 国产a在亚洲线播放 | 日韩欧美视频一区二区 | 老湿影院免费在线观看 | 国产无码在线看 | 天天操狠狠干 | 国产淫秽视频在线观看 | 国产午夜| 三级视频无码 | 日韩国产区 | 国产麻豆剧 | 激情文学图片区 | 午夜三级网 | 丝袜性爱视频 | 午夜视频一区 | 天天操狠狠操夜夜操 | 日韩亚洲人成在线 | 黄色网址免费在线 | 日韩中文字幕电影网站 | 国产小视频在 | 国产三级在线看 | 日韩国产一区二区三区 | 九九九热| 午夜成人视频免费看 | 视频在线一区二区 | 成人无码涩 | 91爱啪| 另类激情图 | 国产无码性 | 日韩先锋影音中文字幕 | 欧美国产精品一区二区 | 国产成人精品AV片 | 五月婷婷网站 | 图片区小说区亚洲 | 超碰人人摸人人搞 | 精品国产乱码一区二区 | 久久高清不卡视频 | 激情小说视频图片 | 欧美成人免费观看视频 | 日韩午夜电影在线一区 | 97蜜桃新版| 久久加勒比视频 | 日韩欧美精品在线 | 人人干人人操超碰 | 午夜成人无码视频 | 日韩淫片| 国产精品久久泡妞网站 | 欧美福利专区 | 97人人操| 免费A级毛片无码专区 | 国产免费毛卡片 | 黄色av网站在线观看 | 日韩电影成人 | 日韩一区二区免费视频 | 日韩电影大全 | 国产性爱精品在线观看 | 五月婷丁香 | 亚洲偷怕自拍 | 黄色天堂在线 | 成人无码一级A片在线 | 91人人操| 欧美另类亚洲 | 国产精品视频二 | 日韩精品91| 91自啪区| 日本中文字幕在线视频 | 偷拍自拍在线视频看看 | 97国产在| 日本中文字幕网站 | 欧美日韩一区二 | 日韩大片免费视频视频 | 97超碰在线播放 | 成人午夜小电影 | 成人高清在线播放视频 | 91视频直播 | 玖玖视频免费 | 午夜福利影院无码 | 国产三级观看 | 国产三级成人 | 午夜手机视频 | 91影视| 欧美不卡一区二区 | 国产91玩精品秘入口 | 国产精品三级片在线 | 国产精伦| 三级黄色片网站 | 日韩高清在线看 | 天天艹夜夜艹 | 国产大神背着在线播放 | 日韩高清电影网 | 日韩高清小视频 | 国产激情视频在线观看 | 天美麻豆最新网址 | 国产高清无码一区 | 日韩一中文字幕 | 午夜福利视频成人视频 | A级片网址| 日韩高清精品在线 | A级毛片免费观看网站 | 日韩在线人成电影大全 | 熟女伦网 | 91视频自拍 | 黄色天堂网站 | 日韩制服丝袜在线观看 | 国产色中色| 欧美V∧| 老湿机啪啪啪视频 | 国产大片好看免费播放 | 亚洲激情文学 | 女同变态另类 | 日本多毛熟妇撒尿 | 午夜福利视频成人 | 韩国理论午夜 | 偷拍综合 | 久久我不卡 | 一区二区视频免费 | 中文字幕加勒比 | 日韩欧美视频一区 | 人妖网站在线 | 伊人狼人干 | 东京无码| 日日干夜夜干 | 夜福利视频导航 | 波多野结喷水 | 成人精品一区在 | 日韩在线播放欧美字幕 | 91精品久久久久久久 | 日韩制服丝袜在线 | 日韩精品欧美在线视频 | 国产主播福利在线观看 | 亚洲精品爆乳无码A片 | 成人三级免费 | 偷拍自拍| 日本黄色电影网站 | 黄色网址在线播放 | 丁香五月影院 | 夜夜干视频 | 免费毛片中文字幕 | 国产午夜视频在 | 日韩欧美国产电影 | 亚洲国产精品成人网站 | 中文字幕第一页国产 | 久久国产精品人妻aⅴ | 午夜福利1000| 麻豆精品在线观看 | 另类一区| 成人免费黃色大片 | 黄色av免费网址 | 久久夜靖品2区 | 日韩aⅴ黄日韩a影片 | 国产午夜视频 | 精品自拍网 | 国产普通话对白 | 成人免费A片 | 欧美性爱地址 | 成人无码一区二区三区 | 女人高潮喷水视频 | 岛国大片在线一 | 天美传奇传媒mv观看 | 午夜福利网在线观看 | 亚洲国产中文在线观看 | 成人欧美精品区二区三 | 91熟女| 日韩电影排行榜 | 欧美亚韩一区二区三区 | 五夜婷婷 | 日韩一区二区区 | 日韩在线 中文字幕 | 日韩欧美亚洲天堂成人 | 日本伊人网 | A片免费毛片 | 国产丝袜一区 | 日韩午夜第一页 | 欧美成人在线视频网站 | 午夜激情影| 日本中文字幕不卡 | 麻豆传媒入口 | 国产自产在线 | 日韩二区视频 | 日韩精品免费专区 | 91官网| 加勒比综合网 | 色婷婷一区 | 三级国产在线 | 日韩午夜视频在线观看 | 福利姬视频免费看 | 国产成年人在线 | 国产精品性爱 | 日韩精品第二页 | 国产三级三级在线观看 | 熟妇成人网 | 国产在线91 | 麻豆传媒在线播放 | 日韩欧美三区 | 91精品秘无码网站 | 日韩精品二| 日韩成人高清二区三区 | 午夜人人 | 日韩伦理剧在线观 | 亚洲精品深夜福利 | 欧美在线视频一区 | 国产精品97 | 日韩精品国产一区二区 | 精品国产一区二区久久 | 久久综合娱乐网 | 成人午夜电影 | 香蕉插逼| 日韩城人网站 | 日韩高清电影 | www国产亚洲精品 | 日韩精品视频专区 | 日韩在线永久免费播放 | 国产精品偷伦免费观看 | 国产成人精品自拍 | 丁香五月网 | 性爱自拍第一区 | 日韩亚洲综合精品国产 | 日韩视频在线一区 | 日韩精品高清第一区 | 夜夜嗨国产 | 午夜天堂影院 | 三级欧美日韩在线 | 性久久AV | 免费福利导航污视频 | 日韩v亚洲v欧美 | 无码人妻AV | 日韩影片欧美在线素人 | 日韩欧美综合一二三区 | 图片小说成人网 | 国产精品网站 | 国产舌乚八伦偷品W中 | 极品精品 | 国产无码三级在线视频 | 日韩精品亚洲专区 | 国产久爱青草视 | 成人特黄A级毛片免费 | 三级在线观看免费大全 | 成人无码三级在线观看 | 三极网站| 国产午夜影视 | 国产盗拍视频一区二区 | 成人一级 | 自拍偷拍免费观看 | 午夜男女羞羞视频 | 欧美国产日韩在线观看 | 免费深夜福利 | 日韩新片快播网 | 97在线资源网 | 午夜看片| 日韩精品中文不卡视频 | 日韩精品2 | 国产探花在线看 | 99自拍视频 | 午夜婷婷网 | 成人a视频 | 日韩成人动漫第一页 | 日韩成人激情影院 | 日韩电影排行榜 | 观看福利影院 | 中文字幕日本网站 | 深夜无码福利 | 国产a不卡片 | 国产性色自拍网 | 五月天婷婷综合网 | 亚洲激情图片 | 玖玖爱国产片 | 国产a片 | 日韩小电影 | 国产成a人亚洲 | 日韩高清精品视频在线 | 九一精品 | 日韩精品欧美大片 | 鲁鲁播放操屄 | 日韩影视传媒在 | A片午夜 | 三级黄色成人网站 | 97蜜桃123| 国产大片视频免费观看 | 精品女同一区 | 激情综合网小说 | 成人高清 | 免费视频福利导航 | sm电影下载| 三级视频网站 | 日韩v欧美v中文在线 | 国产午夜亚洲精 | 国产丨熟女丨国产熟女 | 五月婷婷五月天 | 亚洲精品另类 | 国产精品可站18 | 日韩无码中文字幕 | 在线免费观看福利姬 | 国产三级免费网站 | 日韩无码高清无码 | 日韩在线视频中文字幕 | 国产第九页 | 日韩欧美一区二区在 | 国产69精品亚洲 | 日韩专区午夜福利第三 | 欧美性爱www | 天天干天天弄 | 亚洲清色| 日韩热映专区视频合集 | 国产精品激情在线观看 | 日本成人久久 | 午夜神马伦理 | 激情文学第一页 | 精品自拍1 | 日韩亚洲欧美在线 | 狼友福利免费在线观看 | 国产性爱电影网 | 97超碰人| 日韩专区欧 | 中国三级片免费看 | 国产第3页 | 国产精一精二区 | 午夜福利在线视频 | 国产95在| 尤物视频网站在线观看 | 视频一二区免费 | 日韩无码二区三区 | 国产色情-搜索 | 日韩精品在线播放 | 午夜影视频 | 午夜网址在线观看 | 伦利理午夜理论片 | 成人福利在线看 | 日韩欧美亚洲免费 | 欧美日韩精品喷水 | 狠狠干狼人综合网 | 国产福利在线看 | 国产h视频在| 日韩中文字幕欧美视频 | 国产v片免费播放 | 日韩电影中 | 亚洲图片另类小说 | 午夜在线免费看 | 日韩欧美亚洲综合在线 | 国产无码电影网站 | 可以看A片的网址 | 国产高清视频在线播放 | 日韩国产精品一区 | 成人亚欧网站在 | 日韩有色| 激情小说av| 国产a精品v| 自拍偷拍在线观看视频 | 午夜操一操 | 五月丁香六月婷婷综合 | 欧美精品涩涩瑟瑟 | 91AV视频| 日韩精品一区国产精品 | 91精品久久久久久 | 图片在线视频小说成人 | 亚洲福利 | 成人午夜激情影院 | 无码午夜视频在线观看 | 九一福利 | 日韩穴穴网 | 九色黑人 | 麻豆视频网站在线观看 | 精品久久久久性 | 91偷拍经典 | 婷婷五月丁香综合 | 国产日韩网站 | 国产又黄又猛 | 午夜轮三级 | 三级黄色毛片视频网站 | 日韩精品一站 | 日韩小视频在线观看 | 国产99久9在线视频 国产99久9在线 | 国产精品日韩欧 | www.黄色网址| 九九热精品 | 成人a影院 | 国产高清视频一 | 99热视 | 97青青碰| 天堂资源最新在线 | 日韩理论片在线观看 | 加勒比二区 | 成人高清在线播放视频 | 国产做a精品 | 日日干日日 | 黄片成人片免费 | 亚洲成人小说图片 | 怡红院一区二区三区 | 日韩在线aⅴ免费视频 | 午夜伦理在线观看 | 午夜黄色影院 | 美女黄色毛片 | 日本韩国电影一区二区 | 精品AV| 国产盗摄一 | 成人交性视频免费看 | 玖草视频在线 | 久草青草 | 日韩一欧| 日韩xxxxx级 日韩www视频 | 国产男女猛视频 | 日韩综合国产中文字幕 | 国产丝袜美腿在线 | 日韩伦理片在线观看 | 日韩精品1234 | 老湿机在线看 | 国产嫖妓一区二区三区 | 国产免费一区二区三区 | 日韩精品1| 狼友精品| 国产三极片在线观看 | 国产乱人视频在 | 日韩欧美亚洲妖精 | 国产91精品成人不 | 国产大片特黄高清视频 | 日韩在线精品蜜柚影院 | 国产做爱在线 | 成人一级 | 成人一级午夜 | 麻豆视频在线观看 | 国产精品另类 | 国产h片在线 | 91网址| 伪娘一区二区 | 91久久国产 | 日本91视频 | 日韩成年人视频 | 视频一区欧美 | 国产偷拍自拍在线观看 | 国产亚洲免费看 | 国产TS变态重口人妖 | 婷婷五月天网址 | 国产xxx在线观看 | 日韩在线高清视频蜜桃 | 国产爆乳在线播放 | 东京热欧美 | 岛国大片在线播放免费 | 成人一区二免费视频 | 91直播最新版 | 国产高潮白浆喷 | 天天干狠狠干 | 精品丝袜在线 | 日韩视频一区二区三区 | 日韩高清精品在线 | 日韩电影导航 | 91香蕉小视频 | 国产又爽又粗又猛又色 | 日韩电影在线看 | 国产一区免费 | 久久主页 | 日本高清视频色 | 午夜黄色 | 欧美牲爱 | 国产一级a | 中文国产 | 亚洲性一区 | 国内视频不卡免费国 | 午夜福利一区 | 成人中文在线电影网 | 成人欧美一区二区三 | 日韩精品不卡一 | 午夜伦不卡 | 人妻一区二区三区 | 日韩伦理大全 | 国产精品一区二区小说 | 午夜色婷婷 | 69成人天堂无码免费 | 成人无码做爰毛片国产 | 成人窝窝午夜 | 午夜精品在线观看 | 午夜福利院电影 | 成人伊人网 | 亚洲国产影院 | 国产精选第一页 | 日韩大片在线玫瑰影视 | 成人国产高清在线 | 成人影片在线观看 | 91中文字幕 | 亚洲精品亚洲人成人网 | 午夜草草 | 日韩中字中文字幕在线 | 免费欧美精品 | 黑人大茎大战40 | 成人艳情一二三区 | 日韩欧美aⅴ不卡视频 | 国产在线不 | 日韩欧美国产手机在线 | 国产专区一 | 日韩福利在线观看 | 久草国产在线视频 | 日韩综合网 | 国产一区视频在线播放 | 亚洲激情小说 | 精品无码一级毛片免费 | 午夜在线小视频 | 日韩福利在线视频播放 | 三级片在线观看视频 | 午夜视频网 | 日韩精品中文一区二区 | 精品成人一区二区三区 | 精品人妇一区二区三区 | 东京热系列 | 欧美孕妇三级网 | 老湿机网址 | 东京热乱| 成人国产综 | 三级在线专区 | 日韩欧美偷拍精品一区 | 一级做受视频 | 欧美a在线 | 日韩午夜在线高清成人 | 日韩在线一区天天看 | 国产情侣在视频 | 在线久草 | 日韩理论在线播放 | 精东影业免费一级A片 | 无码2025| 三级视频在线观看 | 日逼天堂 | 国产在线看 | 欧美性爱黑人 | 国产在线无码一区 | 国产精品成人无码免费 | 国产爆乳美女娇喘 | 成人免费ā片在线观看 | 日本高清色www | 国产亚洲免费看 | 国产三级在线观看 | 97国语精品 | 日韩国产另类激情图区 | 日韩另类国产 | 欧美另类精品 | 日韩在线综合另类 | 日韩欧美国产第二区 | 成人精品无 | 午夜视频播放器 | www97超碰| 91神马| 夜夜干夜夜 | 午夜在线视频0 | 内射美女在线 | 久久字幕 | 日韩中文字幕高清一区 | 91丝瓜app| 一二区免费视频 | 福利片在一区二线观看 | 成人论坛| 成人导航在线观看 | 日韩精品1 | 日韩精品电影亚洲一区 | 日韩国产欧美亚洲v片 | 日韩欧美一中文在 | 日韩精品在线观看视频 | 91啦中文| 亚洲无码无卡 | 国产精品成 | 超碰成人人人操 | 午夜十八岁禁 | 91视频网页版 | 成人国产亚洲 | 夜福利导航| 国产精品xxxx | 国产丝袜福利 | 日韩欧美免费 | 国产亚洲精品…3 | 欧美性爱黑人性爽 | 日韩亚洲一分钟 | 精品动漫一区 | 国产二区视频 | 午夜无码在线观看视频 | 成人国产无线视 | 午夜福利在线观看影院 | 日韩无码中文字幕 | 福利所视频导航 | 日韩无码不卡 | 欧美在线精品一区 | 亚洲有码在线 | 日韩一级大片亚洲 | 国产v片在线播放 | 国产熟女性爱 | 日韩大片在线观看入口 | 日韩a级片视频 | 成人a在线观看 | 都市激情中文字幕 | 久热青草 | 91豆奶| 中国三级在线观看 | 久草免费福利 | 可以在线看的黄色网址 | 五月婷婷六月综合 | 成人午夜高清在线观看 | 国内外成人在线视频 | 色偷偷资源 | 日韩成人精品免费观看 | 成人韩免费网站 | 高潮国产| 福利一区视频在线观看 | 国产极品国产极品 | 成人青草亚洲国产 | 国产美女视频网站 | 日本精品中文字墓 | 日韩伦理片视频 | 国产清草 | 尤物在线视频 | 日韩a级一片| 日韩无人区 | 岛国大片网站在线观看 | 综合偷拍| 专干老熟人300部 | 成人午夜福利视频网站 | 午夜成人免费福利 | 日韩欧美在线导航 | 国产成人一区二区无码 | 国自产偷拍精品 | 午夜美女影院 | 午夜福利成人在线 | 坡多野结衣 | 日韩精品另类天天更新 | 日韩欧美制服中文 | 激情文学成人网 | 国产激情文学 | 日韩亚洲中文午夜 | 成人播放日韩在线观看 | 国产第一福利影院 | 日本不卡一区二区三区 | 日韩欧美电影网 | 色屋视频 | 日韩精品免费专区 | 日韩免费一区 | 日韩高清精品视频在线 | 成人国产视频一区二区 | 国产在线激情 | 激情婷婷网 | 国产白领| 国产第一视频 | 日韩伦理片影院 | 人妖伪娘亚洲另类综合 | 中文字幕一区在线 | 伊人91 | 精品国产一二区 | 国产网站视频 | 九色导航| 九九九成人 | 成人毛片网 | 成人图片视频小说 | 成人激情五月 | 国产一区久久 | 天天做天天干 | 三级黄色在线播放 | 日韩精品第二页 | 超碰97观看| 成人不卡免费观 | 国产高潮视频在线观看 | 操欧洲女人 | 国产免费人成 | 麻豆传媒视频入口 | 日韩经典电影 | 国产精精 | 天堂网在线免费资源 | 秘密福利网址导航 | 日韩大片欧 | 国产成年人在线观看 | 狠狠艹AV | 极品尤物丰满暴露尤物 | 国产成人精品水 | 久爱青草| 日韩系列第一页 | 日韩欧美精品一区二区 | 日韩精品福利在线 | 91粉嫩玉足夹精脚交 | 国产你懂得 | 午夜免费激情 | 超碰人人草97 | 91中文在线| 国产又大又黄又猛又爽 | 成人午夜免费观看 | 午夜激情成人网 | 天天操天天日天天干 | 国产三级精品视频 | 国产香蕉人人 | 日韩国品一| 亚洲卡一卡二在线观看 | 日韩精品3| 搞鸡网站在线观看 | 国产福利第一视频 | 欧美日韩国产一区 | 日韩欧美视频免费看 | 中国三级片那里看 | 成人精品在| 国产性爱精| 日韩欧美激情兽交 | 日韩欧美另 | 日韩一级在线精品国产 | 成人免费体验 | 五月丁香亚洲综合 | 午夜成人影视在线 | 日韩一区二区电影 | 日韩亚洲欧美精品性爱 | 午夜黄影院| 国产a级片 | 日韩午夜电影在线一区 | 国产宾馆在线观看 | 中文字幕日韩有码 | 日韩在线视频中文字幕 | 午夜无码福利在线观看 | 黄色三级网络 | 精品国产一二区 | 国产69精品福利 | 日韩国产精品视频 | 日韩精品1 | 三级AV| 丁香五月天论坛 | www性久久| 精品处破女学生 | 91视频聊天 | 日韩精品三级在线观看 | 国内自拍第三页 | 天堂无码高清视频 | 东京热色 | 日韩国产私拍在线观看 | 日韩在线观看视频 | 国产ts人妖赵恩静在 | 天天艹夜夜艹 | 香蕉久操 | 91网视频| 激情小说成人 | 激情小说另类图片 | 在线观看偷拍自拍 | 午夜福利免费在线 | 天堂网在线看 | 亚洲国产精品99久久 | 国内91视频 | 五夜婷婷 | 日本韩国欧美中文字幕 | 日韩欧美亚洲0 | 国产精品成人在线观看 | 亚洲成人内射 | 成人精品视频在 | 日韩欧美偷拍精品一区 | 哦哦哦好爽国产人妖 | 麻逗传煤永久播放 | 国产精品精品精品 | 亚洲国产精品-8 | 五月婷婷六月丁香花 | 亚洲国产精品在线 | 国产性爱电影在线观看 | 国产AV淫乱兄妹 | 日韩欧美亚洲精品 | 午夜成年人网站 | 亚洲激情第一页 | 亚洲国产A片 | 视频一区视频二区视频 | 日韩欧美黄 | 国产情侣酒店自拍视频 | 国产精品成人AV片 | 日韩精品中文字幕 | 日韩欧美亚洲国产一区 | 国内外成人在线视频 | 在线观看三级网址 | 超碰97成人在线 | 欧美性爱第5页 | 日韩亚洲一区二区三区 | 日韩中文字幕在线亚洲 | 日韩美女主播 | 就去啪国产在线 | 九九九九色 | 日韩免费一级 | 国产a级免费视频 | 欧美性爱视频网址 | 久久综合影视 | 精品三级片在线观看 | 日韩日屄视频 | 国产网站三级片 | 亚洲图片激情文学 | 日韩精品免费看 | 尤物网址 | 首页-91n | 91手机在线 | 国产色情在线 | 伦理片一区二区 | 日韩精品丝袜第一页 | 午夜三级伦理片 | 国产精品成人在线 | 国产亚洲无码精品 | 日韩一区二区三级 | 黃色成人大片色 | 日韩视频在线观看一区 | 国产呦福利呦交 | 萌白酱柚木国产精品 | 日本免费xxxx | 日韩电影免| 五月激情综合网 | 日韩无码高清无码 | 在线精品秘 | 美女在线网站 | 五月天成人社区 | 日韩欧美视频二区 | 国产在线免费看 | 国产白丝在线 | 日韩亚州欧美中文字幕 | 日韩aⅴ高清在线观看 | 东京热www. | 久草免费资源站 | 成人欧美日韩 | 国产第11页| 日韩一区精 | 欧美性爱第八页 | 中文字幕成人动漫 | 成人精品久久 | 三级精品视频在线播放 | 99视频自拍 | 又黄又爽的视频 | 国产成年女人免费 | 午夜成人影院 | 四虎影成人精品A片 | 日韩成人观看 | 国产大神背着在线播放 | 日韩网站在线播放 | 91国内| 能看的黄色网址 | 极品免费视频 | 日韩欧美动漫一区二区 | 韩国日本三级在线 | www.97超碰在线 | 日韩亚洲欧美在线观 | 性爱网站在线看 | 欧美视频色 | 日韩国产在线观看 | 成人污污污在线观 | 午夜三级伦理片 | 日本簧片 | 草莓视频成人版 | 成人毛片免费看 | 欧美黄色三级网站 | 欧美性生活网站 | 成熟的国模冰莲[2] 成人做爰黄片免费看 | 日韩电影在线观看视频 | 尤物网址在线观看 | 亚洲国产精品成人网站 | 福利吧导航 | 国产ts人妖赵恩静在 | 97高清国语自产拍 | 东京热官方网站 | 成人黄色免费视频 | 国产成人影片在线观看 | 中国三级片在线观看 | 午夜三级网| 日韩片免费 | 欧美精品日韩一区二区 | 国产情侣在视频 | 国产免费三级永久免费 | 日韩电影中文 | 日本丰满熟妇xxx | 91伊人久久 | 91色逼| 欧美成人网站在线播放 | 欧美成人免费网站 | 国产青春片大片 | 亚日韩精品 | 国产片在线观看 | 黄色网址在线观看免费 | 国产精品第三页 | 日韩人妖精品一区二区 | 久久影院中文字幕 | 日韩视频在线观看视频 | 国产精品一区二区免费 | 欧美成人免费观看 | 国产又爽又黄 | 成人蘑菇国产 | 成人片a免看 | 欧美另类xxx | 99精品自拍| 日韩加勒比 | 日韩美女色 | 韩日一区 | 中国三级片免费 | 午夜视频网站 | 在线播放福利 | 午夜无码国产 | 日韩在线网| 韩国日本三级网站 | 国产三级午夜理伦三级 | 久久精华一曲二曲三曲 | 国产xxxx在线观看 | 爱豆精品秘国产传媒 | 91亚洲精品国偷拍 | 中字毛片 | 日韩成人不卡 | 国产一区二 | 亚洲国产三级在线观看 | 日韩丝袜性爱在线观看 | 偷拍自拍首页 | 国产人妖视频 | 动漫精品一区 | 人人摸人人操人人干 | 日本在线www | 玖玖88综合在线 | 午夜韩国伦理片 | 自拍偷拍2025| 日韩不卡1卡2卡三卡 | 91原创| 日韩精品视频新区乱码 | 97素材 | 97国语精品 | 国产理论片在线观看 | 亚洲精品亚洲人成人网 | 黄色三级片网址 | 日韩精品电影在线观看 | 久久国产精品影院 | 福利看片 | 日韩一卡2卡 | 日韩欧美啪啪操 | 丝袜中出制服人妻美腿 | 国产成年女人免费 | 国产一区在线观看视频 | 久草资源福利站 | 做爱网站在线播放 | 老女人丨91丨九色 | 日韩a优精品在线观看 | 日韩中文字幕精品a | 精品无码av | 日韩在线精品 | 日韩伦理中文字幕 | 日韩欧美国产片 | 俄罗斯无码 | 黄色毛片免费看 | 国产自拍伦理 | 日韩精品一卡2卡 | 国产夫妻片 | 国产污站| 日韩操碰 | 国产日韩欧美 | 深夜成人福利视频 | 日韩精品福利片午夜免 | 91影视在线 | 午夜成人视频在线观看 | 国产大片免费观看 | 麻豆精品视频在线观看 | 国产一区视频在线 | 99精品视频在线观看 | 日韩亚洲产在线观看 | 欧美高清三区 | ww.色日本| 国产免费三级在线 | 蜜桃一区 | 在线三级网址 | 亚洲国产精品99久久 | 亚洲成人激情小说网 | 日韩精品在线视频 | 日韩午夜片 | 国产日韩网站 | 国产高清无码在线观看 | 国产电影三级在线观看 | 成人香蕉网 | 日韩国产在线不卡高清 | 国产91精品秘入口 | 国产情侣在线视频 | 国产第一区| 免费成人午夜视频 | 91精品久久久久久 | 日韩美女视频在线播放 | 成人国产一区二区三 | 午夜爽爽视频 | 国产一级内射视频 | 日韩精品视频二区 | 欧美日韩三区 | 国产在线第一页 | 成人影片在线免费观看 | 福利视频在线导航 | 午夜天堂影院 | 自拍偷拍第六页 | 极品尤物丰满暴露尤物 | 深夜性爱福利 | 亚洲无码国产精品 | 国产原创区 | 丝袜美腿中文字幕 | 日本乱伦三级片 | 国产三级在线电影 | 日韩电影伦理 | 国产狼友视频在线观看 | sm在线电影 | 成人免费高| 国内精品福利视频 | 天天操狠狠操 | 人伦无码| 国产在线不 | 国产AV剧情 | 午夜AV电影 | 丰满多毛的大陰户特写 | 成人理伦 | 国产午夜福利视频 | 国产视频麻豆 | 一区二区在线 | 国产精品剧情一区 | 日韩在线入口 | 成人免费观看一区二区 | 国产va在线播放 | 日韩亚洲一分钟 | 日韩福利局二区视频 | 国产成人精品三级 | 高潮视频在线观看 | 91视频大全 | 国产精品线路一 | 日韩草莓天堂在线观看 | 成人午夜在线视频网站 | 国产丰满岳 | 日韩欧美国产师生制服 | 成人三级网站在线 | 午夜福利成人影院 | 成人激情五月天 | 免费做受视频 | 三级全黄三级bd | 午夜影院体验区 | 视频区小说区图片区 | 国产三级午夜理伦三级 | 主播视频一区 | 国产性爱影院 | 日韩精品一区二 | 国产成人影视在线观看 | 国产精品福利 | 性盈盈影院在线观看 | 自拍偷拍日韩 | 国产做爱在线 | 日韩亚洲中文高清 | 成人片影院 | 日韩精品专区线上观看 | 三妓网站 | 国产福利片在线观看 | 日韩国产欧美区一区二 | 日韩专区一区 | 福利精品视频视频 | 日韩a级电影 | 国产三级成人在线观看 | 爆乳二区 | 午夜免费成人电影 | 福利姬视频在线看 | 国产视频91| 日韩精品久久久 | 亚洲五月丁香 | 国产青青草在线 | AV在线一区二区三区 | 欧美精品二区三区 | 国产91精品新入口 | 东京久久| 日韩有码中文字幕精品 | 老司机天堂 | 日本有码在线 | 无码不卡久久久久 | 久久综合中文 | 日韩成人免费三级 | 日韩美女直播 | 狼友视频免费在线观看 | 国产网站无码 | 日韩福利片 | 日韩黄色精品 | 精品视频一区二区 | 国产日产欧产美 | 日韩无码中字 | 屁屁国产 | 午夜成人免费无码视频 | 午夜影院体验区 | 福利导航在线观看视频 | 国产99在| 欧美性爱黑人 | 狠狠操亚洲 | 国产成精品| 日本在线观看www | 国产美女一区 | 成人做爰黄片免费观看 | 五月深爱激情网 | 日韩高清区 | 欧美乱伦网站 | 国产人妖网| 日韩美女在线视频一区 | 四虎入口 | 日本a黄| 日韩成人影院影音先锋 | 国产精品久久久久久久 | 国产又黄又粗的视频 | 日韩午夜福利成人 | 日韩国产一区 | 黑人巨茎大战欧美洋妞 | 国内揄拍国内精品 | 自拍亚洲 | 在线观看无码不卡视频 | 国产三区视频 | 老司机午夜福利 | 日韩午夜第一页 | 日韩国产亚州欧美 | 色偷偷资源网站 | 国产精品欧美久 | 97超碰人人操人人干 | 日韩综合第一页 | 国产成人色 | 国产精品成人AV片 | 国产性爱八区 | 三级在线无码观看 | 日韩午夜片 | 国产精品自拍无码 | 日韩免费毛 | WWW97干| 国产va观看在线播放 | 国产成人三级在线播放 | 日本精品中文字墓 | 日韩精品一二三 | 91桃色污无 | 天天日天天操天天干 | 福利视频导航在线观看 | 国产精品狼友 | 日韩乱伦网站 | 午夜激情网 | 日韩在线视频二 | 韩国福利专区 | 亚洲成人AV在线 | 日韩在线观看网址 | 久久精品国产一区二区 | 日韩免费成人 | 主播视频一区 | 在线欧美不卡 | 国产欧美一区二区在线 | 夜夜操夜夜爽 | 91视频入口| 成人三级片在线观看 | 五月丁香婷婷综合 | 涩涩屋在线观看视频 | 日韩伦理电影在线观看 | 激情视频小说网 | 午夜成人电影在线观看 | 久久网中文 | 亚洲综合日韩精品国产 | 成人午夜婬片100集 成人午夜亚洲精品无 | 日本人妻乱码 | 自拍偷拍第二页 | 国产精品美乳在线 | 三级黄色在线播放 | 91最懂男| 国产草草 | 91无码| 国产精品秘麻豆免费版 | 国模视频一区二区 | 国产99不卡 | 韩国三级片精选久久 | 欧美日韩精品一区二 | 免费成人黄片 | 偷拍自拍在线视频观看 | 日韩国产欧美熟女 | 国产色情一区二区三区 | 91视频手机 | 91社网| 岛国大片在线一 | 欧美黑人性爱视频 | 干逼91| 国产性爱在线观看 | 婷婷五月花 | 国产精品性 | 国产成人精品AV | 国产乱子视频 | 日韩在线观看高清视频 | 日韩欧美国产激情视频 | 操欧洲女人 | 成人网站三级片 | 日韩城人视频 | 成人三级在线视频 | 日韩一区二精品成人免 | 国产A区 | 日韩精品抠| 日韩中文有码高清 | 日韩精品三区四区 | 国产少萝视频麻豆 | 强奸乱伦一区 | 成人午夜免费观看一区 | 91自拍刺激 | 日韩欧美亚洲一区精品 | 国产黃色a片三級三 | 三级片网站在线观看 | 老湿机在线免费观看 | 欧美另类综合 | 91在线观看免费高清 | 亚洲品质在线观看 | 成人免费一级A片 | 91直播网 | 亚洲国产成人aⅴ | 亚洲福利网 | 日屄视频网 | 国产第四页 | 日韩精品电影在线 | 成人A片视频| 国产传媒果冻天美传媒 | 日韩成人国产精品视频 | 国产喷浆抽搐 | 91一区二区| 国产2页| 激情综合五月 | 另类潮喷 | 激情小说视频网 | 日韩欧美在线91 | 国产激情一区 | 91福利导航 | www.日| 国产精品亚洲精品 | 韩日精品一二三 | 国产自精品 | 国产丰满岳 | 日韩AV在线三区 | 日韩aⅴ免费一区二区 | 国产成年一级电影 | 亚洲国产网站在线观看 | 日本不卡的中文字幕 | 国产91网站在线 | 日韩高清精品 | 国产三级影院 | 午夜福利导航在线观看 | 成人精品视频最 | 岛国电影一区二区三区 | 日韩无码伦理片 | 日韩欧美亚洲每 | 国产视频538 | 日本激情网站 | 成人午夜在线观看视频 | 国产va| 精品午夜 | 欧美精品一区二区三 | 精品国产乱码一区 | 国产91区| 黃色成人大片色大 | 韩日成人网站 | 精品女同 | 成人在线三级 | 午夜福利网站在线观看 | 国产免费美女视频 | 国产精品酒店视频 | 国产999在线观看 | 欧美成人免费在线观看 | 日本久久一道 | 爱豆传媒影院 | 日韩综合在线 | 日韩高清无 | 国产a∨无 | 日韩欧美在线中文字幕 | 国产精品成熟老 | 日韩伦理片在线观看 | 国产三级片视频 | 精品免费囯产一区二区 | 国产人妖在线观看 | 日韩在线视频第一页 | A级在线免费 | 欧美不卡在线视频 | 国产黄色片网站 | 日韩成人三级在线观看 | 国产美女主播 | 日韩成人午夜剧场 | 夜色福利在线视频 | 国产九区 | 国产ts人妖网站 | 久操精品在线观看 | 天堂网毛片视频 | 日韩欧美aⅴ不卡视频 | 日韩第八页 | 狼友在线视频 | 日韩欧美中文一区 | 国产乱轮网址 | 国产第4页 | 在线观看国产h | 国产又粗又猛又爽又黄 | 自拍偷怕网站 | 玖草电影 | 日韩亚洲精品第一页 | 玖玖在线视频免费观看 | 成人国产在线 | 性欧美孕妇一二三四区 | 三级片国产在线看 | 午夜免费影院 | 婷婷五月综合网 | 国产aⅴ永久无 | 成人猫咪社区 | 日韩精品一区二区三区 | 91视频电影 | 欧美极品性爱网 | 日韩在线不卡看 | 国产黄色在线免费观看 | 岛国三级 | 日av一区二区 | 国产孕妇一区二区三区 | 成人午夜性影院 | 日韩一区二区在线视频 | 日韩成人一级 | 日韩精品电影一区二区 | 日韩综合视频在线观看 | 日韩最热国产在线 | 国产激情网站在线观看 | 日韩精品偷拍一区二区 | 亚洲成人无码在线观看 | 成人午夜看片在线观看 | 日韩一区二区三区av | 成人国产精品秘久久 | 尤物视频在线观看视频 | 国产小视频在 | 三级在线观 | 国产精品秘麻豆免费版 | 国产视频福利 | 91亚洲精品| 日韩高清在线免费观看 | 加勒比综合在线 | 日韩精品免费一级视 | 日韩精品第二页 | 激情图片小说网站 | 成人免费试看 | 久夜视频| www日本高清 | 成人免费观看网欧美片 | 日韩成人免费精品视频 | 91怎么下载| 日韩精品视 | 色悠悠网 | 另类极品人妖 | 国产精品电影网 | 三级国产国语在线观看 | 日韩一二三区的经济 | 日韩国产精品 | 欧美另类综合网 | 国产XXXXXXBD| 深夜福利国产小视频 | 日韩有码中文字幕精品 | 国产足交在线观看 | 国产少萝视频麻豆 | 成人网站一区二区 | 国产精品三级在线播放 | 国产伦理剧 | 国产无码三级在线视频 | 日韩性爱在线视频 | 日韩亚洲一区在线观 | 国产区一区二 | 日韩一区国产精品 | 日韩电影第一页 | 午夜影院 | 海的味道国产精品 | 四虎8848| 成人午夜免费在线视频 | 麻豆网站在线观看 | 国产精品嫩草影视 | 国产精品性 | 国产精品二三区 | 欧美孕妇一区二区 | 日韩黄色视频 | 欧美日韩精品在线 | 日韩高清精品在线 | 国产又黄又粗又爽 | 日韩国际精品一区二区 | 欧美成区 | 国产成人a亚洲AV | 国产亚洲精品…3 | 人人超人人超碰国产 | 午夜成人网站 | 最新版天堂资源在线 | 玖玖在线视频 | 玖玖在线视频免费观看 | 国产又大又粗 | 天天拍天天干 | 日韩美女热舞 | 夜夜干,夜夜操 | 日韩欧美亚洲免费在线 | 亚洲性爱网站 | 亚洲综合精品国产 | 国产成人情趣 | 高潮久久久久久久不卡 | 老湿机免费看 | 国产白丝网站 | 三级黄色在线网站 | 日韩乱码在线观看 | 国产人成| 日韩伦理大片 | 伦理一区二区三区 | 日韩激情不卡一区二区 | 国产亚洲日韩在线 | 四虎影成人精品A片 | 日韩午夜专区 | 亚洲无码国产精品 | 日韩欧美小电影 | 韩国无码无遮挡 | 成人三级在哪里看 | 国产大片欧美精品 | A片在线观看网址 | 日韩欧美性爱网站 | 国产91自拍视频在 | 午夜精彩视频 | 成人午夜免费在线视频 | 成人毛片免费观看视频 | 日韩一区二区三区射精 | 国产又白又嫩又爽又黄 | 日韩欧美国产一区呦呦 | 黄色综合网 | 国产手机精品视频 | 日韩欧美视频在线 | 国产诱惑在线观看 | 日韩在线精品国产一区 | 日韩在线永久免费播 | 日本三级片东京热 | 国产免费三级片完整版 | 99自拍视频在线 | 九九黄色 | 国产拳交在线 | 不卡免费视频 | 日韩在线国产精品 | 国产免费av在线 | 亚洲精品传媒 | 91视频聊天室 | 中文有码在线 | 日韩aⅴ精品国内在线 | 日韩电影大全 | 日韩成电影在线观看 | 国产在线女主播 | 黄色网址无码 | 亚洲性网站 | 国产99视频精品 | 成人永久免费视频 | 深夜成人福利在线观看 | 国产精品自拍在线 | 日韩小网站 | 亚洲女人网 | 美女精品视频 | 三级在线观看国产 | 欧美性爱www | 91社区影院| 精品国产成人 | 国产女主播一区二区 | 日韩国产精品有吗在线 | 国产超级| 日韩欧美国产动漫在线 | 日韩中文在线 | 国产91线观看 | 91香蕉短视频 | 福利精品国产自产在线 | 日韩精品国产另类专区 | 免费福利视频导航 | 天天插夜夜操 | 成人视频毛片 | 成人免费视频播放 | 成人精品在线免费观看 | 亚洲综合导航 | 黄色三级视频网站 | 福利姬图库入口 | 91最新网址 | 高清无码一卡二卡 | 五月丁香六月天 | 日韩国产欧美视频 | 福利精品 | 丁香五月婷婷五月 | 激情小说网址 |