99精品久久精品一区二区-亚洲熟妇无码?v在线播放-日本国产精品无码字幕在线观看-久久久亚洲永夜AV-亚洲一级无码一区二区一-免费国产成高清人在线视频-中文字幕乱码免费观看-国产毛片精品妇女久久久

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營的一線實(shí)戰(zhàn)洞察。

WPF界面框架分層實(shí)踐:主題Token、MVVM與換膚避坑

WPF界面框架分層實(shí)踐:主題Token、MVVM與換膚避坑 簡介面向 WPF 桌面應(yīng)用開發(fā)者的一套現(xiàn)代化界面框架源碼與示例適合希望擺脫默認(rèn)控件外觀、快速搭建統(tǒng)一視覺風(fēng)格的中級(jí)開發(fā)者參考也可作為團(tuán)隊(duì) UI 規(guī)范與主題定制的基礎(chǔ)。壓縮包約 1.84MB共 336 個(gè)文件以 143 個(gè) C# 源碼與 115 個(gè) XAML 界面文件為主體另含 15 個(gè) csproj 工程文件、圖標(biāo)與圖片素材、Visual Studio 項(xiàng)目模板及少量說明文檔覆蓋控件實(shí)現(xiàn)、窗口外殼、主題資源到可復(fù)用模板的完整鏈路。目前已有 6464 人學(xué)習(xí)下載。內(nèi)容圍繞現(xiàn)代化窗口、菜單、對(duì)話框與過渡動(dòng)畫控件展開涉及主題外觀管理與系統(tǒng)版本適配等模塊可據(jù)此理解樣式模板、資源字典與 MVVM 在真實(shí)項(xiàng)目中的組織方式并直接改造為自己的應(yīng)用外殼。1. 一個(gè)漂亮的 WPF 界面框架漂亮之外到底解決什么問題上個(gè)月幫一個(gè)內(nèi)部工具做收尾功能全跑通了評(píng)審時(shí)被一句話打回來這套 WPF 界面看著像十年前的。真正動(dòng)手改才發(fā)現(xiàn)難點(diǎn)不在畫得好看而在主色散落在二十多個(gè) XAML 里、按鈕存在三套模板、每個(gè)窗口的標(biāo)題欄各寫各的。這份 WPF 界面框架源碼包就是把這堆散件整理成三層主題 Token、控件模板、窗口外殼再配一套 MVVM 骨架和若干示例頁。它主要解決兩件具體的事改一處顏色不用翻遍工程新頁面照著示例拼就能交付。適合正在用 WPF 做桌面端、要把界面從「能跑」推到「能驗(yàn)收」的人不適合想找拖拽式設(shè)計(jì)器、指望完全不寫 XAML 的人。2. 拆目錄結(jié)構(gòu)主題 Token、控件模板、窗口外殼這三層怎么分拿到一個(gè)界面框架先別急著運(yùn)行 Demo也別急著往自己的工程里復(fù)制。先看Themes目錄的層次因?yàn)樗鼪Q定了后面所有覆蓋、換膚、定制動(dòng)作能不能生效。這套框架的劃分是比較典型的做法Tokens放純值顏色、字號(hào)、圓角、間距、控件高度Controls放控件樣式與ControlTemplateSkins放皮膚覆蓋Shell放窗口外殼與標(biāo)題欄。分層的意義在于職責(zé)邊界清晰Token 里不該出現(xiàn)任何ControlTemplate控件模板里不該出現(xiàn)任何寫死的#2F6FED。我見過太多項(xiàng)目的資源字典是一個(gè)幾千行的Styles.xaml顏色、模板、動(dòng)畫、轉(zhuǎn)換器全塞在一起。這種文件在項(xiàng)目第三個(gè)月就會(huì)變成黑匣子誰都不敢刪任何一行因?yàn)椴恢绖h了會(huì)影響哪個(gè)頁面。分層不是潔癖是為了讓你敢改。2.1 先看資源字典的合并順序它決定后面所有覆蓋能不能生效WPF 在MergedDictionaries里查找同一個(gè) Key 時(shí)后加入的字典優(yōu)先級(jí)更高。這條規(guī)則很短但它是整套換膚機(jī)制的基石。很多人的皮膚切換做不出來原因就一個(gè)把皮膚字典加在了 Token 字典前面于是 Token 里的舊值一直勝出換膚看起來「沒反應(yīng)」。正確的合并順序是先 Token再 Controls最后 Skin。!-- App.xamlxmlns 省略實(shí)際工程里按模板生成的寫 -- Application.Resources ResourceDictionary ResourceDictionary.MergedDictionaries !-- 第 1 層純值沒有任何模板。換膚就是換這一層的值 -- ResourceDictionary SourceThemes/Tokens/Colors.Default.xaml/ ResourceDictionary SourceThemes/Tokens/Typography.xaml/ ResourceDictionary SourceThemes/Tokens/Metrics.xaml/ !-- 第 2 層控件模板只允許引用第 1 層的 Key -- ResourceDictionary SourceThemes/Controls/Button.xaml/ ResourceDictionary SourceThemes/Controls/TextBox.xaml/ ResourceDictionary SourceThemes/Controls/Card.xaml/ !-- 第 3 層皮膚覆蓋第 1 層同名 Key必須放最后 -- ResourceDictionary SourceThemes/Skins/Light.xaml/ /ResourceDictionary.MergedDictionaries /ResourceDictionary /Application.Resources這段順序背后有兩條必須記住的規(guī)則。第一條是查找方向MergedDictionaries的檢索是從后往前所以最后加載的皮膚能蓋住前面所有同名 Key。第二條是作用域Application.Resources是全局的窗口和控件會(huì)逐級(jí)向上查找一旦某一層出現(xiàn)了同名 Key上層的就永遠(yuǎn)取不到——調(diào)試時(shí)「樣式在別的頁面正常、就這個(gè)頁面不對(duì)」八成是這個(gè)頁面的Window.Resources里藏了一個(gè)同名項(xiàng)??绯绦蚣脮r(shí)路徑要改成 pack URI比如pack://application:,,,/YourApp;component/Themes/Tokens/Colors.Default.xaml程序集名寫錯(cuò)的話運(yùn)行時(shí)會(huì)拋IOException而不是編譯錯(cuò)誤這也是常見的第一道問題。2.2 顏色、字號(hào)、圓角三組 Token為什么主色要用 DynamicResourceToken 層只做一件事把「設(shè)計(jì)決定」變成「命名常量」。這套框架里大致是三類鍵名前綴即語義分類示例 Key典型值說明顏色Color.Accent.Base#2F6FED主色另配 Hover、Pressed 兩檔顏色Color.Surface.Card#FFFFFF卡片、面板底色字號(hào)Font.Size.Body13正文另有 Caption 12、Title 18圓角Radius.Control6按鈕、輸入框統(tǒng)一圓角間距Space.Unit8所有間距取它的整數(shù)倍尺寸Metric.Control.Height32單行控件標(biāo)準(zhǔn)高度主色不要只給一個(gè)值Hover 和 Pressed 要手調(diào)出來別用Opacity疊。原因是透明疊加的結(jié)果依賴背景色同一個(gè)按鈕放在白色卡片和深色側(cè)欄上淺色疊加出來的效果完全不同深色背景上會(huì)發(fā)灰。這是很常見的視覺問題單看沒問題一放到深色區(qū)域就顯得臟。!-- Tokens/Colors.Default.xaml -- ResourceDictionary xmlns... xmlns:x... !-- 主色三檔Hover/Pressed 手工調(diào)深保證在深色和淺色背景上都成立 -- Color x:KeyColor.Accent.Base#2F6FED/Color Color x:KeyColor.Accent.Hover#245BD0/Color Color x:KeyColor.Accent.Pressed#1C48A8/Color !-- Brush 單獨(dú)一層控件模板里用 Brush換膚時(shí)只換 Brush 即可 -- SolidColorBrush x:KeyBrush.Accent.Base Color{StaticResource Color.Accent.Base}/ SolidColorBrush x:KeyBrush.Accent.Hover Color{StaticResource Color.Accent.Hover}/ SolidColorBrush x:KeyBrush.Text.OnAccent Color#FFFFFF/ SolidColorBrush x:KeyBrush.Surface.Card Color#FFFFFF/ !-- 字號(hào)與度量數(shù)值型 Token 用 sys:Double必須帶命名空間 -- sys:Double x:KeyFont.Size.Body13/sys:Double sys:Double x:KeyFont.Size.Title18/sys:Double CornerRadius x:KeyRadius.Control6/CornerRadius sys:Double x:KeyMetric.Control.Height32/sys:Double /ResourceDictionary關(guān)鍵在于「顏色」和「畫筆」分成兩層。Color是不可變結(jié)構(gòu)體SolidColorBrush才是控件屬性真正吃的東西模板里引用的必須是 Brush。數(shù)值型 Token 要注意類型x:Double需要引入sys命名空間clr-namespace:System;assemblySystem.Runtime不同目標(biāo)框架程序集名略有差異CornerRadius直接寫元素即可不用額外命名空間?,F(xiàn)在說DynamicResource和StaticResource怎么選這是最常被問的一個(gè)問題。結(jié)論是會(huì)隨皮膚變化的 Key 用DynamicResource永不變的 Key 用StaticResource。StaticResource在 XAML 解析時(shí)就把值取出來定死換膚后不會(huì)重新求值所以把主色用StaticResource引到模板里切皮膚必然失敗DynamicResource每次取值走一次資源查找會(huì)帶來額外開銷在DataGrid單元格模板、ItemsControl項(xiàng)模板這種會(huì)實(shí)例化成千上萬次的地方能靜態(tài)就靜態(tài)。我的習(xí)慣是Token 里跟顏色相關(guān)的全用DynamicResource字號(hào)、圓角、間距這類換膚不動(dòng)的用StaticResource。這個(gè)劃分一句話能記住后面維護(hù)的人也不會(huì)亂改。2.3 拆一個(gè)按鈕從 Token 到 ControlTemplate 的完整鏈路理解了層次再拆一個(gè)具體控件看看這套框架里一個(gè)主按鈕是怎么拼起來的。這段值得逐行讀因?yàn)樗呛竺嫠锌丶哪0濉?-- Controls/Button.xaml只引用 Token不出現(xiàn)任何字面色值 -- Style x:KeyButton.Primary TargetTypeButton Setter PropertyHeight Value{StaticResource Metric.Control.Height}/ Setter PropertyMinWidth Value72/ Setter PropertyPadding Value16,0/ Setter PropertyFontSize Value{StaticResource Font.Size.Body}/ Setter PropertyForeground Value{DynamicResource Brush.Text.OnAccent}/ Setter PropertyBackground Value{DynamicResource Brush.Accent.Base}/ Setter PropertyBorderThickness Value0/ Setter PropertyCursor ValueHand/ Setter PropertyTemplate Setter.Value ControlTemplate TargetTypeButton Border x:NameBd Background{TemplateBinding Background} CornerRadius{StaticResource Radius.Control} SnapsToDevicePixelsTrue ContentPresenter HorizontalAlignmentCenter VerticalAlignmentCenter Margin{TemplateBinding Padding} RecognizesAccessKeyTrue/ /Border ControlTemplate.Triggers !-- 順序有講究后定義的觸發(fā)器優(yōu)先級(jí)更高 -- Trigger PropertyIsMouseOver ValueTrue Setter TargetNameBd PropertyBackground Value{DynamicResource Brush.Accent.Hover}/ /Trigger Trigger PropertyIsPressed ValueTrue Setter TargetNameBd PropertyBackground Value{DynamicResource Brush.Accent.Pressed}/ /Trigger Trigger PropertyIsEnabled ValueFalse Setter TargetNameBd PropertyOpacity Value0.45/ Setter PropertyCursor ValueArrow/ /Trigger /ControlTemplate.Triggers /ControlTemplate /Setter.Value /Setter /Style這里有幾個(gè)容易被忽略的細(xì)節(jié)每一個(gè)都可能變成后期幾分鐘甚至幾小時(shí)地去排查的問題。第一TemplateBinding是單向的、不支持轉(zhuǎn)換器且只能綁到模板化父級(jí)的屬性上。所以Padding能綁Background能綁但如果你想把Background轉(zhuǎn)成漸變就必須換成{Binding Background, RelativeSource{RelativeSource TemplatedParent}}再掛 Converter?;煊眠@兩者時(shí)不要抱有僥幸心理模板里一旦出現(xiàn)轉(zhuǎn)換需求就整體換成Binding。第二觸發(fā)器順序決定最終效果。IsMouseOver和IsPressed同時(shí)為真時(shí)后定義的IsPressed生效所以按下色必須寫在懸停色后面。反過來寫按下時(shí)看到的還是懸停色看起來就像「按下沒反饋」。第三IsEnabledFalse時(shí)如果只改OpacityCursorHand依然生效鼠標(biāo)移上去還是手型用戶會(huì)以為可以點(diǎn)。所以禁用態(tài)要順手把Cursor也改回來這類細(xì)節(jié)在驗(yàn)收時(shí)最容易被挑出來。最后控件模板里不要出現(xiàn)字面色值這是硬性約束。只要模板里出現(xiàn)一個(gè)#2F6FED換膚那一刻它就會(huì)變成色塊不一致的元兇而且很難靠肉眼定位到具體是哪個(gè)模板??蚣芾镞@類違規(guī)用一次文本搜索就能找出來接入前先搜一遍#順手清理掉。3. 接入現(xiàn)有工程從復(fù)制目錄到跑出第一個(gè)頁面3.1 目錄落位與 csproj 里的資源聲明把整個(gè)工程復(fù)制進(jìn)來是最快的驗(yàn)證方式但真正接入現(xiàn)有項(xiàng)目時(shí)建議只復(fù)制Themes和Infrastructure兩個(gè)目錄示例頁按需挑選著拿。目錄放在項(xiàng)目根下即可不要塞進(jìn)Properties或者obj旁邊obj目錄在清理時(shí)容易誤刪。csproj這塊有個(gè)高頻問題SDK 風(fēng)格工程的默認(rèn) glob 已經(jīng)把**/*.xaml編譯成Page你再手寫一遍Page IncludeThemes\**\*.xaml /就會(huì)報(bào)重復(fù)項(xiàng)NETSDK1022。所以大部分情況下什么都不用寫只在需要排除或者改變構(gòu)建方式時(shí)才動(dòng)它。ItemGroup !-- 默認(rèn) glob 已包含 **/*.xaml這里只做排除草稿目錄不參與編譯 -- Page RemoveThemes\_draft\**\*.xaml / !-- 字體、圖標(biāo)這類二進(jìn)制資源用 Resource隨程序集嵌入pack URI 才取得到 -- Resource IncludeAssets\Fonts\*.ttf / Resource IncludeAssets\Icons\*.png / !-- 示例數(shù)據(jù)用 Content 復(fù)制到輸出目錄別用 Resource 塞進(jìn)程序集 -- Content IncludeSampleData\*.json CopyToOutputDirectoryPreserveNewest / /ItemGroup構(gòu)建項(xiàng)的選擇直接決定資源能不能取到這張表建議存下來構(gòu)建項(xiàng)編譯結(jié)果適用場景取用方式Page編譯為 BAML所有 XAML包括資源字典Source相對(duì)路徑Resource嵌入程序集字體、圖標(biāo)、小圖片pack://application:,,,/程序集;component/路徑Content原樣復(fù)制到輸出目錄示例數(shù)據(jù)、可替換配置相對(duì)輸出目錄的路徑None不處理文檔、說明無字體用Resource嵌入之后在 XAML 里通過FontFamily/Assets/Fonts/#字體內(nèi)部名引用注意斜杠后面那個(gè)#后面跟的是字體家族名不是文件名。寫錯(cuò)了不會(huì)報(bào)錯(cuò)只會(huì)靜默回退到系統(tǒng)默認(rèn)字體——這類靜默失敗最耗時(shí)間。3.2 App.xaml 合并字典與運(yùn)行時(shí)換膚皮膚切換不要用「先清空再添加」的寫法。清空MergedDictionaries會(huì)在瞬間讓所有DynamicResource失效控件重繪時(shí)可能拋出找不到資源的異常而「只添加不移除」會(huì)讓字典越積越多切換五十次之后內(nèi)存和查找開銷都會(huì)肉眼可見地上漲。正確做法是把皮膚字典固定在MergedDictionaries的最后一位換膚就是替換這一項(xiàng)。public static class ThemeManager { // 皮膚字典固定放在 MergedDictionaries 的末位替換這一項(xiàng)即為換膚 private static readonly Uri LightSkin new(pack://application:,,,/YourApp;component/Themes/Skins/Light.xaml); private static readonly Uri DarkSkin new(pack://application:,,,/YourApp;component/Themes/Skins/Dark.xaml); public static void Apply(bool dark) { var merged Application.Current.Resources.MergedDictionaries; if (merged.Count 0) return; var skin new ResourceDictionary { Source dark ? DarkSkin : LightSkin }; // 關(guān)鍵替換而不是 Add避免字典無限增長 merged[merged.Count - 1] skin; } }替換完成后不需要手動(dòng)刷新任何控件DynamicResource會(huì)自動(dòng)重新求值。這里有個(gè)前提所有隨皮膚變化的引用必須是DynamicResource只要模板里漏了一個(gè)StaticResource換膚后那個(gè)控件就會(huì)保持舊色在一片新配色里顯得很突兀。還要注意換膚的時(shí)機(jī)。啟動(dòng)時(shí)在App構(gòu)造函數(shù)里調(diào)用是最穩(wěn)的如果放在窗口Loaded之后用戶會(huì)看到一次明顯的閃爍。真想做到無閃爍就得在窗口顯示前把皮膚定好也就是把配置讀取提前到App初始化階段。3.3 無邊框窗口外殼與自定義標(biāo)題欄這套框架的外殼用的是WindowChrome而不是WindowStyleNone加AllowsTransparencyTrue。后者雖然也能做出無邊框效果但會(huì)讓窗口失去硬件加速路徑拖動(dòng)和縮放時(shí)明顯發(fā)澀圓角邊緣還會(huì)有鋸齒。WindowChrome保留系統(tǒng)窗口的非客戶區(qū)行為只把繪制權(quán)交給你。!-- Shell/AppWindow.xaml無邊框外殼保留系統(tǒng)縮放與拖拽行為 -- Window x:ClassYourApp.Shell.AppWindow WindowStyleNone ResizeModeCanResize AllowsTransparencyFalse Background{DynamicResource Brush.Surface.Card} !-- CaptionHeight頂部可拖拽區(qū)高度等于標(biāo)題欄高度 -- !-- ResizeBorderThickness邊緣拖拽熱區(qū)觸屏場景建議放大到 8 -- WindowChrome.WindowChrome WindowChrome CaptionHeight40 ResizeBorderThickness6 GlassFrameThickness0 CornerRadius0 UseAeroCaptionButtonsFalse/ /WindowChrome.WindowChrome Grid Grid.RowDefinitions RowDefinition Height40/ RowDefinition Height*/ /Grid.RowDefinitions !-- 標(biāo)題欄區(qū)域內(nèi)的按鈕必須聲明 IsHitTestVisibleInChrome否則點(diǎn)不到 -- StackPanel Grid.Row0 OrientationHorizontal HorizontalAlignmentRight WindowChrome.IsHitTestVisibleInChromeTrue Button Content— Style{StaticResource Button.Caption}/ Button Content□ Style{StaticResource Button.Caption}/ Button Content× Style{StaticResource Button.Caption}/ /StackPanel ContentPresenter Grid.Row1 Content{Binding Body}/ /Grid /Window三個(gè)參數(shù)決定了使用手感。CaptionHeight要和標(biāo)題欄那一行的高度嚴(yán)格對(duì)齊寫 40 就是 40寫小了頂部會(huì)剩一條既不能拖也不能點(diǎn)的死區(qū)ResizeBorderThickness在鼠標(biāo)場景 6 夠了觸屏設(shè)備建議 8 到 10否則邊緣拖不動(dòng)GlassFrameThickness0去掉系統(tǒng)玻璃層避免深色皮膚下邊緣發(fā)亮。標(biāo)題欄里的按鈕必須加WindowChrome.IsHitTestVisibleInChromeTrue這一條不加按鈕會(huì)變成「看得見點(diǎn)不著」鼠標(biāo)事件被拖拽區(qū)吃掉了。這是無邊框窗口最常見的一個(gè)問題排查時(shí)容易往命令綁定上想繞一圈才發(fā)現(xiàn)是命中測試。另一個(gè)是最大化蓋住任務(wù)欄。無邊框窗口最大化時(shí)系統(tǒng)給的尺寸包含非工作區(qū)直接鋪滿會(huì)頂?shù)羧蝿?wù)欄。簡單的做法是在窗口構(gòu)造里設(shè)MaxHeight SystemParameters.MaximizedPrimaryScreenHeight多顯示器場景下這個(gè)值只在主屏正確需要監(jiān)聽WM_GETMINMAXINFO自己算工作區(qū)框架的Shell目錄里有對(duì)應(yīng)的輔助類接入時(shí)按屏幕數(shù)量確認(rèn)一下。3.4 驗(yàn)收入口DPI、縮放、多屏的檢查清單界面框架接進(jìn)去功能點(diǎn)兩下都正常不代表能交付。下面這張表是我每次接入必過的一遍成本不到十分鐘能提前擋掉大部分返工。檢查項(xiàng)操作不通過的表現(xiàn)單屏 100%系統(tǒng)縮放調(diào)到 100%逐頁翻一遍1px 邊框消失或變粗單屏 150%縮放到 150%看文字與圖標(biāo)文字發(fā)虛、圖標(biāo)模糊多屏不同縮放兩屏分別設(shè) 100% 和 150%拖窗口來回拖到另一屏后整體變糊高對(duì)比度切換系統(tǒng)高對(duì)比度主題文字與背景同色看不見觸摸觸屏設(shè)備上點(diǎn)邊緣縮放邊緣拖不動(dòng)最小尺寸拖到最小寬高標(biāo)題欄按鈕被擠出可視區(qū)DPI 那一欄解釋一下WPF 是邏輯像素體系縮放變化時(shí)如果圖片資源只準(zhǔn)備了一份系統(tǒng)會(huì)拉伸結(jié)果就是模糊。圖標(biāo)盡量用矢量路徑位圖則按 100%、150%、200% 各備一份靠Image的尺寸選擇邏輯去匹配。這條不做用戶在 150% 縮放的筆記本上第一眼就會(huì)覺得「這軟件有點(diǎn)舊」。4. MVVM 骨架命令、通知、導(dǎo)航與對(duì)話框怎么切界面層的活干完接著看骨架。這套框架的Infrastructure目錄里放的是一套很薄的基礎(chǔ)設(shè)施ViewModelBase、RelayCommand、AsyncCommand、導(dǎo)航服務(wù)、對(duì)話框服務(wù)。判斷一套 MVVM 骨架好不好標(biāo)準(zhǔn)只有一條ViewModel 里能不能完全不出現(xiàn)Window、MessageBox、Application.Current。出現(xiàn)了單測就廢了復(fù)用也別想了。4.1 ViewModelBase屬性通知與 SetProperty 的寫法public abstract class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; // 返回 bool方便 setter 里鏈?zhǔn)酵ㄖ缮鷮傩?protected bool SetPropertyT(ref T field, T value, [CallerMemberName] string? name null) { // 用 EqualityComparer 而不是 object.Equals避免值類型裝箱 if (EqualityComparerT.Default.Equals(field, value)) return false; field value; OnPropertyChanged(name); return true; } protected void OnPropertyChanged([CallerMemberName] string? name null) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); }CallerMemberName省掉了手寫屬性名字符串改屬性名時(shí)不會(huì)漏改通知。相等判斷用EqualityComparerT.Default而不是因?yàn)榉盒屠飳?duì)值類型是裝箱比較屬性高頻更新時(shí)這點(diǎn)開銷會(huì)積少成多。返回bool是個(gè)很實(shí)用的小設(shè)計(jì)if (SetProperty(ref _name, value)) OnPropertyChanged(nameof(DisplayName));這樣派生屬性只在真正變化時(shí)通知避免無謂的綁定刷新。老項(xiàng)目里常見的寫法是 setter 里連續(xù)調(diào)三次OnPropertyChanged每次輸入都觸發(fā)一輪完整重算。集合屬性是另一個(gè)問題點(diǎn)。ObservableCollectionT不要每次賦值都new那等于讓ItemsControl重建整個(gè)視圖樹滾動(dòng)位置會(huì)跳回頂部。正確做法是初始化一次之后用Clear()加Add()更新。4.2 RelayCommand 與 AsyncCommandCanExecute 刷新時(shí)機(jī)的坑public sealed class RelayCommand : ICommand { private readonly Actionobject? _execute; private readonly Funcobject?, bool? _canExecute; public RelayCommand(Actionobject? execute, Funcobject?, bool? canExecute null) { _execute execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute canExecute; } public bool CanExecute(object? parameter) _canExecute?.Invoke(parameter) ?? true; public void Execute(object? parameter) _execute(parameter); public event EventHandler? CanExecuteChanged { add CommandManager.RequerySuggested value; remove CommandManager.RequerySuggested - value; } // 手動(dòng)觸發(fā)異步命令結(jié)束、集合變化后必須調(diào) public void RaiseCanExecuteChanged() CommandManager.InvalidateRequerySuggested(); }CommandManager.RequerySuggested是隱式刷新只在鍵盤、鼠標(biāo)等輸入事件之后觸發(fā)。這意味著如果你在后臺(tái)線程里改了某個(gè)標(biāo)志位按鈕的可用狀態(tài)可能要等到用戶點(diǎn)一下別的地方才更新。血淚經(jīng)驗(yàn)是異步命令執(zhí)行完畢、批量數(shù)據(jù)加載完成這類時(shí)刻必須顯式調(diào)一次RaiseCanExecuteChanged()否則用戶會(huì)看到「按鈕還是灰的但功能其實(shí)已經(jīng)好了」。異步命令額外要處理兩件事。一是防重入執(zhí)行中把CanExecute置為false避免用戶連點(diǎn)三次發(fā)出三個(gè)請(qǐng)求。二是異常兜底async void里拋出的異常會(huì)直接打到未處理異常上進(jìn)程就掛了??蚣芾锏腁syncCommand用try/catch包住執(zhí)行體把異常交給注入的錯(cuò)誤處理器再由它彈提示。public sealed class AsyncCommand : ICommand { private readonly Funcobject?, Task _execute; private readonly Funcobject?, bool? _canExecute; private bool _isRunning; // 防重入標(biāo)志 public AsyncCommand(Funcobject?, Task execute, Funcobject?, bool? canExecute null) { _execute execute; _canExecute canExecute; } public bool CanExecute(object? parameter) !_isRunning (_canExecute?.Invoke(parameter) ?? true); public async void Execute(object? parameter) { if (_isRunning) return; _isRunning true; RaiseCanExecuteChanged(); try { await _execute(parameter); } catch (Exception ex) { // 必須兜住async void 里的異常無處可去 ErrorHandler?.Invoke(ex); } finally { _isRunning false; RaiseCanExecuteChanged(); } } public event ActionException? ErrorHandler; public event EventHandler? CanExecuteChanged; public void RaiseCanExecuteChanged() CanExecuteChanged?.Invoke(this, EventArgs.Empty); }AsyncCommand我沒有復(fù)用CommandManager而是自己維護(hù)CanExecuteChanged。原因是異步場景下按鈕狀態(tài)變化跟輸入事件沒有必然關(guān)系走隱式刷新容易失準(zhǔn)自己控制雖然要多調(diào)幾次RaiseCanExecuteChanged但行為可預(yù)期。4.3 導(dǎo)航與對(duì)話框接口怎么切才不綁死 UI接口切分的目標(biāo)是讓 ViewModel 只描述「要什么」不描述「怎么顯示」。這張表是框架里的切法接口職責(zé)不該做的事INavigationService按 ViewModel 類型切換主區(qū)域內(nèi)容不引用具體Page、Window類型IDialogService確認(rèn)框、輸入框、等待提示不直接調(diào)MessageBoxINotificationService頂欄消息、Toast不持有具體控件的引用IThemeService讀取與切換皮膚不碰Application.Resources的索引public interface IDialogService { // 返回 Task調(diào)用方 await 之后拿結(jié)果避免回調(diào)地獄 Taskbool ConfirmAsync(string title, string message); Taskstring? PromptAsync(string title, string message, string? defaultValue null); }實(shí)現(xiàn)側(cè)常見的做法是用一個(gè)覆蓋全窗口的ContentControl加半透明遮罩把對(duì)話框內(nèi)容當(dāng)作普通控件渲染返回值靠TaskCompletionSourcebool在用戶點(diǎn)擊時(shí)SetResult。這樣對(duì)話框也吃同一套 Token深色皮膚下不會(huì)出現(xiàn)一個(gè)白底黑字的系統(tǒng)彈窗視覺上跳出來。這里要提醒一點(diǎn)TaskCompletionSource必須用TaskCreationOptions.RunContinuationsAsynchronously否則SetResult會(huì)在 UI 線程上同步跑完整個(gè)await后續(xù)邏輯遇到重活就卡界面。這個(gè)問題非常隱蔽表現(xiàn)為「點(diǎn)確認(rèn)之后界面頓一下」把選項(xiàng)加上就好。5. 避坑記錄樣式不生效、內(nèi)存上漲、DPI 模糊的排查順序這一章是這份框架里最值得先讀的部分。下面四條都是我在真實(shí)接入里遇到過的每一條按現(xiàn)象、原因、解決的順序?qū)懹龅酵悊栴}時(shí)可以照著順序查。5.1 現(xiàn)象改了 Token控件紋絲不動(dòng)現(xiàn)象把Color.Accent.Base從藍(lán)改成橙重新生成主按鈕還是藍(lán)的。清緩存、重啟 IDE 都試過仍然是藍(lán)。原因控件模板里引用的是{StaticResource Brush.Accent.Base}。StaticResource在 BAML 解析階段就把值取出來寫死了后續(xù)字典變化對(duì)它沒有任何影響。另一種可能是這個(gè)頁面的Window.Resources里定義了一個(gè)同名的Brush.Accent.Base局部作用域優(yōu)先全局的改動(dòng)被它遮住。解決在解決方案里搜StaticResource Brush.凡是顏色類的引用全部換成DynamicResource再逐頁檢查Window.Resources和UserControl.Resources里有沒有同名 Key。這兩步做完改動(dòng)立即生效。我的習(xí)慣是把這條寫進(jìn)代碼評(píng)審清單模板里出現(xiàn)StaticResource后面跟Brush.前綴的一律打回。5.2 現(xiàn)象切幾次皮膚內(nèi)存一路往上走現(xiàn)象在設(shè)置頁反復(fù)切換淺色和深色任務(wù)管理器里的內(nèi)存從 180MB 漲到 400MB 不回落切得越多漲得越多。原因換膚實(shí)現(xiàn)寫成了merged.Add(skin)每次切換都往MergedDictionaries里追加一個(gè)字典舊字典既沒被移除也沒被回收資源查找還得從后往前遍歷一長串。另一個(gè)隱性原因是畫筆沒凍結(jié)SolidColorBrush每次創(chuàng)建都是新的可凍結(jié)對(duì)象沒調(diào)Freeze()就參與變更通知無法被共享。解決換膚改成替換末位元素見 3.2 的寫法Token 里所有SolidColorBrush在創(chuàng)建后調(diào)一次Freeze()凍結(jié)后的畫筆可以被多個(gè)控件共享內(nèi)存占用會(huì)明顯下降。改完再測反復(fù)切換五十次內(nèi)存曲線基本走平。提示Freeze()只能用于可凍結(jié)對(duì)象而且凍結(jié)后不能再改屬性。如果某個(gè)畫筆需要在運(yùn)行時(shí)調(diào)色就別凍結(jié)它。5.3 現(xiàn)象4K 屏上字體發(fā)虛、1px 邊框消失現(xiàn)象開發(fā)機(jī) 100% 縮放一切正常換到 150% 縮放的筆記本上正文明顯發(fā)糊卡片之間的 1px 分隔線時(shí)有時(shí)無圓角處還有毛邊。原因三個(gè)疊加問題。位圖圖標(biāo)只準(zhǔn)備了一份系統(tǒng)拉伸導(dǎo)致模糊Border的BorderThickness用了1但沒開UseLayoutRounding和SnapsToDevicePixels在非整數(shù)縮放比下 1px 被攤到兩個(gè)物理像素上顏色被稀釋到看不見再就是窗口設(shè)了AllowsTransparencyTrue透明窗口在部分縮放下失去硬件渲染路徑。解決圖標(biāo)改用矢量路徑在外殼根元素上開UseLayoutRoundingTrue需要像素對(duì)齊的Border和Image加SnapsToDevicePixelsTrue無邊框窗口換回WindowChrome方案。三條一起改150% 下再對(duì)比截圖邊緣和文字都恢復(fù)銳利。5.4 現(xiàn)象設(shè)計(jì)器里正常運(yùn)行時(shí)拋 XamlParseException現(xiàn)象XAML 在設(shè)計(jì)器里預(yù)覽得好好的一運(yùn)行就拋XamlParseException提示找不到某個(gè)資源堆棧指向一個(gè)看起來沒問題的Setter。原因StaticResource的解析是編譯期決定的它只能向前查找——引用必須出現(xiàn)在定義之后或者定義在更早就合并的字典里。設(shè)計(jì)器有時(shí)會(huì)更寬松地加載于是出現(xiàn)「設(shè)計(jì)器能看、跑起來就崩」。另一種原因是跨程序集引用時(shí) pack URI 里的程序集名寫錯(cuò)編譯期不校驗(yàn)運(yùn)行時(shí)才爆。解決先在App.xaml里把 Token 字典排在最前面確保所有模板在后面再檢查所有跨程序集的Source程序集名、大小寫、component關(guān)鍵字都要對(duì)上。定位技巧是把App.xaml里的合并字典臨時(shí)注釋掉一半二分法很快能鎖定是哪個(gè)文件。5.5 常見問題速查表癥狀第一嫌疑快速驗(yàn)證換膚后個(gè)別控件不變色模板里用了StaticResource全工程搜StaticResource Brush.按鈕點(diǎn)不動(dòng)標(biāo)題欄命中測試被吃檢查IsHitTestVisibleInChrome最大化蓋住任務(wù)欄無邊框窗口的尺寸計(jì)算看MaxHeight是否按工作區(qū)算列表刷新后滾動(dòng)條跳頂集合被整體new檢查ObservableCollection賦值處命令按鈕一直灰隱式刷新未觸發(fā)手動(dòng)調(diào)一次RaiseCanExecuteChanged字體不是預(yù)期那個(gè)FontFamily的家族名寫錯(cuò)核對(duì)#后面是家族名而非文件名6. 進(jìn)階把換膚做成可以回歸驗(yàn)證的流程界面類的改動(dòng)最難驗(yàn)證因?yàn)樗缚雌饋頉]問題」和「確實(shí)沒問題」之間差得很遠(yuǎn)。這套框架里我最常用的一個(gè)技巧是把換膚做成可以對(duì)比的回歸流程。第一步把 Token 抽出來做一份中間格式??蚣艿腡okens目錄本身就是鍵值對(duì)用幾十行代碼掃一遍 XAML把Color.*、Font.Size.*、Radius.*導(dǎo)出成 JSON交給設(shè)計(jì)側(cè)對(duì)齊。之后設(shè)計(jì)師改配色改的是這份 JSON工程師用腳本回寫 XAML比在群里發(fā)色值截圖靠譜得多?;貙懩_本要注意保留原有的x:Key順序和縮進(jìn)否則每次生成都是幾百行 diff評(píng)審時(shí)沒人看得下去。第二步準(zhǔn)備一個(gè)「Token 全覽頁」。把所有 Token 渲染成色塊、字號(hào)樣例、圓角樣例配上鍵名放在調(diào)試菜單里。換膚以后直接翻這一頁哪個(gè)鍵沒被覆蓋一眼就能看出來。這個(gè)頁面我一般不到半小時(shí)就能拼完但省下來的排查時(shí)間遠(yuǎn)超投入。第三步截圖比對(duì)。把關(guān)鍵頁面在淺色和深色下各截一張存在版本庫里改了樣式之后重新截用逐像素差值定位變化區(qū)域。閾值不要設(shè)在零字體渲染有亞像素抖動(dòng)允許千分之三以內(nèi)的差異超過就是真改了。這套流程跑順之后改一個(gè) Token 影響哪些頁面提交前就能知道。還有一個(gè)小習(xí)慣值得說一下每次接入新的界面框架我都會(huì)先在空工程里跑一遍它的 Demo把所有頁面點(diǎn)一遍重點(diǎn)看深色皮膚下的對(duì)比度和禁用態(tài)。原因很簡單這些地方最容易藏問題而在自身工程里樣式問題會(huì)被業(yè)務(wù)邏輯掩蓋很難判斷到底是框架的問題還是你寫錯(cuò)了。從那以后我每次往項(xiàng)目里引 UI 框架都強(qiáng)制先走一遍這套空工程驗(yàn)證再動(dòng)業(yè)務(wù)代碼。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
日本玖玖在线| 五月丁香六月成人| 久久久网站| www。88热在线视频免费观看| 99天堂在线观看免费视频| AV网站免费在线| www.狠狠色.com| 99日精品视频| 91丁香| 午夜天堂一区人妻| 人妻中文在线| 久久九九色| 日日夜夜狠狠| 月婷婷婷婷五月| 婷婷色五月噜噜| 综久久久| 丁香五月婷婷www..com| av不卡网站| 婷婷久久色| 九九热视频精品| 开心久久五月天| 99在线综合视频| 五月丁香六月婷| 婷婷五月AV| www、色色色| 丁香六月婷婷综情欧美| 婷婷五月天成人在线视频| 91VIP在线观看| 九九热精品| 99视频在线播放大全| 五月婷婷黄色视频| 人人操人人爱丁香五月| 五月婷婷 激情五月| 青青草a在线| 日本啪啪天堂| 热的国产99热| 丁香五月综合在线播放| 蜜臀嫩草| 天天爱天天做天天操| 国产日日操夜夜操的肉棒视频| 婷婷五月天最新综合你懂的| 丁香五月狠狠综合欧美| 六月天丁婷婷| 色婷婷五月天偷拍| 婷婷午夜天| 97操在线视频| 丁香婷婷久久| 日本97在线看片| 草草女人亚洲| 久久全色| 婷婷五月天黄色| 色碰干| 1区2区视频| 大香蕉人人网| 五月丁香六月综合情在线观看| 人人澡玖玖一| 婷婷九月激情网| 亚洲艹网| www.丁香五月| 丁香色五月 97干| 婷婷久久丁香五月| 亚洲视频一区| 99小视频在线观看| 婷婷久久五月天| 就要去操亚洲成人精品五月天丁香婷婷| 久热99| 五月天激情网图片 - 百度| 婷婷五月丁香在线观看| 色播五月网| 91婷婷色 | 99久久.www| 久色激情| 亚洲色色色色| 伊人久久大香网| 婷婷五月丁香六月| 婷婷六久久| 久久婷婷的综合色丁香五月| 密黄站| 天天色五月| 亚洲丁香五月| 国产成人99久久亚洲综合精品| 色播播五月天| 色色五月天婷婷丁香| 丁香五月性爱| 天天骑天天操| 人人艹艹艹| 色五月噜噜| 五月丁香激情综合啪啪| 色情五月天se| 丁香婷婷六月天| 97人人干| 五月天综合久久| 亚洲成色综合网站免费观看| 99re热在线观看| 五月综合色| 色婷婷AV在线观看| 深爱激情久久| 婷婷六月综合激情| AAA久久久AAA久久久AAA| 久热欧美| 色欲午夜无码久久久久久张津瑜| AⅤ网站在线看| WWW免费视频碰碰碰碰| 亚洲婷婷五月草久| 日本色色网| www.ywav| 五月婷婷在线网站| 国产全是老熟女太爽了| 五月综合亚洲色| 丁香五月婷婷色偷偷| www.色婷婷| 色色婷婷色色| 99在线亚洲| 五月婷婷五月天| 五月婷九九草| 六月狠狠综合| 色婷婷六月| 男女99免费视频| 五月天激情社区| 激情网五月| 美国不卡视频| 国产精品VA在线| 91 欧美| 婷婷免费精品视频| 亚洲精品99| 九九99热| 99精品热视频| 欧美性爱五月天| 26uuu日韩| 免费看欧美成人A片无码| 婷婷五月天丁香花| 九九激情网| 色一情一乱一乱一区9| 99久久婷婷五月天| 日本在线观看aaa 99| 色婷婷色久综| 久草婷婷网 | 婷婷五月激情丁香| 99爱爱网| 婷婷丁香五月麻豆| a色色色色色| 九九热10| 亚洲五月六丁香激情| 91狠狠色丁香婷婷综合久久| 中海油常州环保涂料有限公司| 五月婷婷啪啪啪| 久久一级片| 婷婷六月综合激情| 亚洲精品成人| 99色在线| 深爱五月日韩| 91久久久久久久91| 国产在这里只有精品| 丁香六月激情| 99热这里是精品| 丁香五月色综合色播五月| 色五月综合| 久久久久久xxxxx| 五月天丁香| 久热这里只有精品3| 五月婷婷深深爱| 99er日韩| 丁香六月综合| 九九RE视频在线精品| 男女99免费视频| 岛国AV网| 夜夜撸日日骑| 日韩综合天堂| 超碰在线观看三级片| 五月丁香激情深爱婷婷| 九九自拍网| 深爱五月天| 五月婷婷丁香伦理网| 疯狂做受XXXX高潮A片动画| 久久亚洲网| 激情性爱五月天网页| 天天做天天爱天天玩夜夜爽 | 色,激情五月天| 色婷婷在线视频| 久久机只有这里精品| 婷婷五月丁香性爱| 五月天色丁香| 天天日夜夜拍| 久久婷婷成人视频| 欧美日韩国产一区二区| 能看的av| 欧美激情综合色综合啪啪五月| 亚洲欧美成人在线| 国产免费av网站| 97碰人人操| 亭亭玉立国色天香| 怡红院成人AV| 午夜天堂一区人妻| 99日本在线| 热久久77777| 亚洲岛国电影| 亚洲色色色| 天天高潮夜夜爽| 国产精品视频免费看| 色色热| 思思热久久久在线| 国产激情综合五月| 亚洲六月婷婷| 熟女国产在线一区二区三区四区| 欧美黑人巨大性生话| 婷婷激情五月色综合| 五月丁香六月综合基地| 婷婷新网址| 大香蕉520| 99热在线成人网站| 99精品无码网站| 大香蕉婷婷五月| 无码激情AAAAA片-区区| 久久九九色| 午夜丁香婷婷| 五月丁香六月婷婷亚洲视频| 五月四色色| 婷婷五月亚洲综合| 日韩综合久久| 在线视频99| 九九热123| 九九热免费| 五月天激情网图片| 激情五月小说婷婷| 九九激情视频| 开心五月深爱激情| 丁香五月天成人| 性色欲情 网站| 九九99热| 成人综合AV| 亚洲av成人一区二区电影在线| 天天爽人人综合免费7799| 五月婷婷综合在线| 野战毛片三一3| 巴基斯坦粉嫰无码视频| 手机看片日日做夜夜| 久久综合激情| 六月婷婷色综合| 蜜桃婷婷狠狠久久| 超碰91人人操| 在线不卡视频| 色五月丁香总合网| 南京搡BBBB搡BBBB| WWW.桔色成人.COM| 99热在线这里| 婷婷五月天小说| 久久开心五月天激情| 久久精品66| 五月婷在线色视频| 五月婷婷久草在线视频综合| 久久婷婷综合五月天| 婷婷丁香五月,狠狠综合| 色亚洲中文| 久热这里这里有精品| 五月天色色激情综合| 日日噜噜夜夜狠狠久久丁香六月| 26uuu欧美日韩| 日韩亚洲视频| 深爱五月中文字幕| 成人超碰Av| 久久色五月天综合网| 激情开心五月亚洲| 可以看的av网站| 亭亭玉月丁香| 99热国产这里只有精品| 国产精品天天狠天天看| 伊人久热91| 人人爽欧美婷婷久久久五月丁香| 色域五月婷婷丁香| AV天堂淫乩| 婷婷六月激情丁香| 99在线免费观看| 九热免费视频| 8090在线影视少妇| 九九激情视频| 丁香婷婷五月天网站| 五月丁香天天| 婷婷内射视频在线| 99精品视频在线观看| 国产精品成av人在线视午夜片| 日本97在线看片| 91综合在线观看| 中文字幕av亚洲| 亚洲中文av| 欧美婷婷五月激情| 狠狠99| 色欲一区二区三区精品A片| 久久综合99| 综合另类激情| 色五月首页| 久久精品在线| 99热这里只有精品8| 五月天婷婷久久| 天天综合网站| 五月婷婷色播| 五月亭亭综合五码| 婷婷五月天伊人| 大香蕉AV电影在线| 欧美婷婷| 夜夜爱网站| 九九热在线精品| 激情五月天婷婷播播久久综合91 | 丁香五月激情婷婷视频| 久久综合人妻| 成人超碰网| 人妻激情视频| 狠狠操狠狠做| 99精品偷自拍| 五月天激情黄色小说在线观看| 久久婷婷午夜| 激情色色| 99视频在线9| 丁香五月日韩| 丁香六月激情国产| 新激情五月天| 就99这里只有精品| 色综合色| 黄色精品五月婷婷| 26uuu精品国产| 丁香六月婷婷久久综合| 亚洲精品电影| 亚洲色夜| 中文字幕无码成人电影| www.ppypp| 欧洲色| 超碰无码318604| 涩涩五| 色综合久久888| 婷久久久| 丁香九月婷婷色| 亚洲天堂热| 五月婷啪啪| 久热这里只有精品视频免费观看| av中文字幕免费观看| 日本欧美在线| 九九热超碰| 秋霞日本免费毛片A片| 久色国产| 九久九精品| 日日噜噜久久婷婷五月天| 青青草tp| 五月丁香六月婷综合成人综合| 亚洲另类毛片| 亚洲另类视频| 亚洲第一影院高清无码网站| 激情五月丁香五月| 99热九九在线| 2020日日干| 色色色色区| 五月丁香龟婷婷| 一级黄在线| 五月婷婷狠天天色综合| 中文中文在线| 66精品成人免费网站在线观看 | 婷婷成人五月天| 五月婷六月综合在线观看| 五月丁香激情四射| 婷婷色导航| AV九九| 大香蕉五月天婷婷| 婷婷99| 激情综合网五月天天| 五月丁香六月在线| 六月婷婷日| 欧美性生交XXXXX无码小说| 桃色伊人在线| 婷婷五月激情综合网| 六月狠狠综合| 超级碰碰碰碰视频| 79精品视频在线观看,| 婷婷六月激情小说网| 天天干天天爽| 天天日天天做天天操| 99青青草99| 丁香六月激情综合啪啪| 怡春院久操| 人人操日| 五月天天天开心激情网| 久9热插入| 色五月成人| 九九99九九99| av国产精品| 99热精品中文字幕| 色色丁香| 丁香五月婷婷操逼| 色五月激情综合网| 久热a| 天综合日日夜综合7799| 色婷婷电影网| 五月天婷婷丁香社区| 碰人人操| 另类少妇人与禽zOZZ0性伦| 激情五月婷婷综合网| 91丨九色丨国产打屁股网站| 99日本精品视频热| 99热精品9| 五月丁香少妇| 色婷婷成人做爰A片免费看网站| 久久婷婷五月综合啪| 丁香五月婷婷偷拍| 色狠狠色综合久久久绯色aⅴ影视| 五月天激情无码| 丁香花色色网| 91久久人人操| 丁香五月婷婷基地| 国产成人高清| 婷婷丁香五月天中文字幕| 91久久精品无码一区二区三区| 婷婷精品视频| 99视频在线播放大全| 丁香婷婷六月激情| 亚洲在线操| 婷婷五月天 丁香五月天 裸体| 综合激情五月婷婷| 亚洲激情免费视频| 婷婷五月天亚洲色| 色婷婷五月开心六月综合| 色色丁香婷婷五月天| 99热超碰在线| 夜夜谢天天干| 丁香五月激情视频| 电影蜘蛛女| av在线免费网站 | 五月婷婷激情综合视频| 99热 在线观看| 在线资源av-超碰中文在线-成人AV | 亚洲av网站| 丁香五月婷婷操逼| 少妇熟女视频一区二区三区| 亚洲操逼片| 日韩欧美骚货| 丁香婷停五月激情综合深爱| 五月天婷五月天综合网小说首页-五月天激激婷婷大综合,婷婷亚洲综合五月天小说 | 香蕉婷婷| 九九久久99精品免费观看www| 五月丁香亭亭天天舔| 丁香婷婷久久| 99日本黄站| 激情丁香五月AV| 狠狠婷婷综合| 91干婷婷| 99re资源在线视频导航| 激婷网| 色色五月婷婷| 丁香六月激情| 欧美经典片免费观看大全| www.婷婷五月| 色情五月丁香| 99热这里只有精品3| 大香线蕉伊人| 99热综合在线| 99激情在线| 99视频只有精品| 一级操逼内射在线视频| 欧美激情综合色丁香婷婷五月天| 牛牛碰免费| 日韩AV色色色| 亚洲成人va| 丁香五月婷婷成人网| 亚洲十月婷婷综合| 九色色| 天天影视色综合网| 精品五月天| 久久99性爱| 99热6这里只有精品| 人人草人人爱手机视频看看| 中文字幕色色| 播播网色播播| 91精品久久久久久久| 99在线观看精品| 96精品久久久久久久久| 婷婷成人五月天成人文学| 99久久这里只有精品| 激情丁香五月天| 国产毛片精品一区二区色欲黄A片| 亚洲色久| 激情电影五月婷婷| 国产老熟妇亲子乱对白| 婷婷6月综合网| 丁香桃色综合网| 天天橾日日橾夜夜橾17| 99视频久久| 任你日视频| 996er热| 色五月情| 亚洲 欧洲 国产 伦综合| 丁香婷婷超碰 | 手机激情网| 狠狠色噜噜| 开心婷婷中文字幕| 婷婷色婷婷| www,黄色在线,con| 欧美色碰| 操操操av| 亚洲天天| 激情五月天视频| 精品一二三区久久AAA片| 操精品9| 激情视频综合| 亚洲99激情| 超碰熟女拍拍| 女人天堂AV| 操逼电影免费看| 天天综合五月| 六月婷婷影院| 丁香婷婷久久 | 色小说婷婷五月天天天| 国产毛片精品一区二区色欲黄A片| 五月综合久久| 97超碰色| 综合五月天亚洲婷婷| 国语精品探花| 99这里有精品视频| 久久9999| 婷婷五月天成人综合网| 久久综合人妻| 在线超碰91| 五月丁香va| 亚洲丁香婷婷丁香五月天激情| 久久久免费精彩视频| www.久操| www.minyis.com【JT】国内CDN落地页保证转化QQ2101460746 | aⅤ79成人片| 久久久久人妻中文| 亚洲AV免费在线| 婷婷成人在线| 婷婷五月骚厕所| 99热9| 五月丁香六月婷婷激情四射| sewuyue第四色| 五月激情综合网| 亚洲人成网站999综合| 激情婷婷| 激情五月综合网最新| 99操九九网| 另类的婷婷| 综合色影| 色九九九九| 久久精品视频9| 91碰碰| 色热久| 五月天精品| 9热成人在线视频| 涩综合在线| 久久婷婷综合网| 日本在线wwww| 亚洲狠狠干| 国产,欧美,学生妹,视频| 五月天激情综合网俺也去| 激情五月丁香亭亭| 99热在线爱| 色99热| 91se精品国产| www狠狠| 欧美成人AAA片一区国产精品| 亚洲综合在线伊人婷| 伊人狠狠丁香婷婷综合尤物| 久久丁香五月| 东京热伊人| 久久久五月五丁香| 婷婷四色五月| 九九人人操| 五月天婷婷久久| AV在线观看网站| 91丨九色丨熟女| 丁香五月天.com| 色爱综合网| 射久久丁香五月| 狠狠干综合| 久草五月天| 亚洲婷婷五月| 色啪影院| 丁香激情网| 欧美婷婷五月激情| 97操碰人免费| 99色网站| 五月丁香色| 激情五月天在线视频| 超碰在线91| 日本婷婷| 91欧美日韩| 六月色播| 大香蕉婷婷丁香天堂AV| 少妇高潮呻吟A片免费看软件| 婷婷天天舔| 日韩中文字幕| www.com五月天| 亚洲AV第二区国产精品| 噜噜视频| 天天干天天爽天天操| 国产成人亚洲综合亚洲| 色五月婷婷久久| 亚洲丁香五月深爱五月| 丁香亚洲色综合| 五月丁香色婷婷色| 亚洲激情 久久| 五月伊人91| 亚洲操B| 婷婷综合网站| 激情五月天婷婷播播久久综合91| 久操97| 久久五月六月| 婷婷五月乱交换| 久久99久久99精品免视看婷| 五月丁香六月婷婷免费| 色综合偷拍| 欧美日综合| 亚洲人成人五月天| 久久黄A片| 97色 五月天丁香| 99男人的天堂| 艾小青av| 99精品热| www.com任你艹| 99热| 亚洲午夜电影| 久久99久久99精品免观看软件| 日本天堂免费99| 丁香六月婷婷| 色哟哟www| 综合久久五月| 亚洲人成网亚洲欧洲无码久久| 色五月婷婷7777| 久久五月网| 五月综合缴情网| 丁香六月婷婷久久综合| 狠干综合| 4438亚洲欧美| 九九色逼| 日本啪啪天堂| 婷婷综合在线| 台湾佬天天日丁香婷婷五月天| 五月丁香无码| 色五月97| 色婷婷亚洲综合天堂| 日日日日日| 久久Xx| 天天天天爽爽天干| 超黄亚洲瑟瑟网站| 婷婷91| 97干在线看| 教师性爱毛片| 情欲禁地| 五月婷婷五月天| 99色热视频| 少妇达人正片在线播放_ikun_福利吧| 激情五月网站| 99re在线观看视频| 久热这里只有精品3| 九九综舍久久| 成人在线视频一区| 久久99免费视屏| 中文字幕无线久必| 人与禽A片啪啪| 五月婷婷基地| 色五月av| 国产乱子轮XXX农村| 久久99网| 婷婷五月天开心网| 五月婷婷激情综合网| 97婷婷狠狠| 伊人久久大香线蕉av一区| 激情综合网五月天| 五月丁香六月综合激情| 99视频这里有精品| 99亚洲精品| 新激情五月天天在线网| 狼友超碰| 9色在线| 色香蕉影院| 97干97色| 激情小说五月天| 99精品网| 99re热视频这里只精品| 亚洲婷婷性爱| 国产亚洲成人综合| 4438国产免费看| 中文字幕欧美久久| 五月婷婷AV| 五月婷俺去也| 日本婷婷丁香五月| 日本熟女一区二区| 激情五月天激情五月天| 久久五月婷婷丁香| 91狠狠色丁香婷婷综合久久精品| 综合色99| WWW.亚洲无码| www.com色播五月天| 亚洲超级碰| 亚洲成人一区| 色五月丁香一区在线| 夜夜操狠狠操天天操| 色狠久| 午夜爱爱网站| 99在线精品观看99| 2015在线中文字幕| 婷婷免费无马| 婷婷五月天777| 丁香五月激情图片| 激情綜合網址| 99性爱视频| 中文婷婷狠狠| 五月丁香999| 五月丁香花伦理电影| 亚洲婷婷激情五月天| WWW.17C亚洲精品| 久久综合九九| 五月综合激情啪啪啪啪啪| 99re青青草| 99re66热这里只有精品| 99热这里只有精品最新地址获取| 婷婷五月天综合久久| 色情成人五月天| 色婷婷五月综合色婷婷| 久久99热这里只有精品首| 亚洲精品久久久久久久久久吃药| 中文字幕,综合,91| 99热在线观看| 激情五月综合久久| 伊人成人宗合网| 五月天婷婷久久| 99成人| 碰人人操| 婷婷五月丁香色情| Av大香蕉| 超碰人人妻| 这里都是精品99| 五月丁香中文| 欧美成人AAA片一区国产精品| 天天干,天天操,天天射| 天天日人人| 五月丁香性爱| 六月丁香开心婷婷欧美| 婷婷5月天av| 亚洲综合无码| 婷婷97C| 五月丁香六月婷婷综合免| www.久久综合| 日韩三级视频一区二区| 五月永久激情| 99精品视频网| 99在线精品视频| 五月丁香无码视频| 黑人巨粗进入警花疼哭A片| 婷婷久久亚洲| 婷婷综合一二三| 影音先锋男士资源网一区| 成人深爱丁香五月| 99自拍视频在线观看| 色色色9 9 9| 26UUU精品一区二区Com| 玖玖在线视频| 永久思思热在线| 丁香五月婷婷色情综合| 五月婷婷六月丁香首页| 婷婷六月五月| 激情综合五月丁香六月婷婷| 美女主播野战视步页| 五月婷婷啪啪| 爱之国产色情综合| 99精品热| 密黄站| 亚洲久热| 99爱视频精品| 丁香五月电影| av九九| 另类视频在线| 国产精品久久..4399| 天天综合 99久久婷婷| 4399欧美另类视频| 天天日天天插| 久婷婷五月综合欧美| www五月| 999久久久国产精品| 久久丁香五月| 婷婷五月激情的图片| 丁香五月婷婷综合精品素人| 亚洲成人网站在线| 99九无网码| 天天久综合网永久入口17v| 原琪琪色影院| 99久视频| 开心五月天激情网| 九九成人精品| 任你爽在线视频| 欧美色爱五月天| 丁香视频| 99视频久久| 九九国产视频| 欧美S码亚洲码精品M码| 五月丁香六月欧美| 婷婷五月a| 久久99久久99精品免观看粉嫩| 成人国产综合| 97人妻碰碰中文无码久热丝袜| 婷婷丁香成人在线视频| 久久免片| 五月婷九月| 99爱精品| 91精品久久久久久综合五月天| 婷色五月天| 亚洲五月综合色播| 婷婷丁香黄色| 色碰碰| 888精品福利地址| 成人超碰网| 色婷婷五月天激情在线观看| 色玖玖综合网| 亚洲精品V天堂中文字幕| 开心五月激情婷婷| 丁香婷婷九月| 极品少妇XXXX精品少妇偷拍| 日日操天天| 青青草色在线视频观看| 国产精品VIDEOSSEX久久发布| 五月香六月婷| 任你爽免费视频| 成人片黄网站色大片免费毛片| 激情五月天激情综合网| 91爱操| AV片一区在线观看| 综合色影| 丰满人妻一区三区三区| 91|九色|动漫| 成人午夜视频精品一区| 六月婷婷中文字幕| 色色色在线免费视频| 伊人超碰在线| 五月天婷婷基地| 五月丁香操亭亭网| 婷婷五月激情热播| 久久久人人操A V| www.婷婷五月天| se99视频| 精品九九在线观看| 天天综合久久| 三级毛片视频| 99色在线观看| 九九婷婷五月天| 丁香六月狠狠| 538任你爽视频不一样的| 偷偷与邻居做爰完整视频| 激情综合网五月婷婷| 婷婷五月天无码视频| 三级毛片7979| 91精选国| 五月婷婷六月天| 操操国产| 色狠狠婷婷| 欧美天天性| 色很很96| 91色逼| 在线超碰精品| 国产五月视频| 日韩啪啪视频| 狼友视频在线观看18| 99热在线观看精品| 开心五月婷婷在线视频免费观看| 九月激情网| 97碰碰电影| 色综合婷婷99| 少妇出轨做爰高潮A片| 亚洲婷婷免费| 97干网站| 五月婷婷导航| 色婷婷亚洲六月婷婷中文字幕| 蜜臀九九九九| 五月香蕉婷婷| 另类五月婷婷| a色色片| 激情av| 中文无码婷婷| 久久激情五月婷婷| 91chinese 在线| 四川操逼站| 色综合久久8| 色域五月丁香| 超碰cap| 99在线视频观看| 久久久久久五月天| 人人摸人人操人人爱| 成熟妇人A片免费看网站| 婷婷综合网站| 五月丁香| 大学生高潮无套内谢视频| 婷婷丁香成人| 亚洲视频在线观看| 一点色成人网| 五月天网址在线刘玥| 亚洲精品白浆高清久久久久久 | 色五月婷婷色| 色婷婷av在线观看| 色婷婷电影网| 桃色成人网| 国产操B| 一区=区操屄高清大全av| 99热99日天天干| 九九综合88| 97热久久五月婷婷| 91九色丨国产丨爆乳| 啊V视频在线观看| 激情婷婷丁香五月天小说| 他改变了拜占庭| 成人婷婷色五月天| 国产精品-91JQ就要激情网91JQ6.91JQ27.CASA:16888 | 思思热精品在线| 丁香五月性爱| 亚洲乱码日产精品BD| 五月天婷婷狂暴白浆| 另类图片五月天激情| 激情综合色婷婷啪啪六月天| 91在线日| 婷婷丁香午夜综合影视| 丁香五月天啪啪激情综和网| 色五月婷婷亚洲| 久久3p| 97婷婷色| 日本44久久在线| 热久69| 亚洲综合字幕色色| 久久狠色噜噜狠狠狠狠97| 五月天婷婷丁香视频| 亚洲综合激情五月| 久久多色| 午夜天堂一区人妻| 五月天怕怕| 日本三级中国三级99人妇网站| 综合欧美五月婷婷| 综合激情深爱| 日本一级一片免费视频| 99热这里只有精品9| 五月婷婷黄网站大全| 九九热re99re6在线精品| 丁香激情久久| 婷婷丁香人妻久久在线观看| 免费看欧美成人A片无码 | 丁香,开心成人,久久| 丁香五月停停基地| 欧洲亚洲免费视频区| 精品色| 六月激情婷婷| 大香久久综合网| 丁香五月婷婷黑人妻黄色电影院| 亚洲mm色| 内射综合网| 97caop| 久久精品五月天| 五月社区丁香| 大香蕉婷婷久久| 610018岁成人视频| 狠狠久久婷五月| 狠婷婷五月| 色色射| 亚洲色五月婷婷| 思思视频精品| 人人97碰| 色9999综合久久| 天天日日人| 婷婷综合成人| 九月激情婷婷丁香| 五月天婷婷色在线视频免费观看 | 五月天社区婷婷丁香社区| 亚洲精品又粗又大又爽A片 | 日韩久久色| 亚洲欧美一区二区三区爱爱动图| 日本综合色图| 六月婷久久| 99re思思热久久| 国产人妻人伦精品一区二区| 丁香五月首页| 激情五月丁香亭亭| 伊人五月婷| 激情婷婷五六月天| AV九九| 91啪啪网| 欧美色色网| 超碰人人摸人人操| 99视频久久免费视频| 久久九九爽| 五月婷婷婷| 激情五月丁香六月综合AVXXXX| 在线观看国产高清视频免费网站 | 94干大香蕉| 丁香婷婷中文字幕| 91久久精品国产91性色TV| 激情婷婷五月女| 综合激情五月天| 色婷婷综合综合网| 99色性爰网络| 97碰碰叉| 五月丁香六月婷婷久久久综合| 国产成人片| 99re思思精品视频在线观看| 婷婷网五月天| 久九色| 97九色| 91美女被操| 婷婷的99视频网站| 久久总和99| 综合久久久| 91免费看片| 亚洲人妻Av| 91丨九色熟女丨首页| 青青草成人网| 色婷婷AⅤ| 激情婷婷丁香| 久99热在线观看| 五月天激情小说| 成人永久免费视频在线观看| 婷婷狠狠97| WWW.久久久久久久| 99热9999| 婷婷五月天久久久| 国产在这里只有精品| 五月婷婷高清| 熟女人妻一区二区三区免费看| 99re这里只有精品免费| 大陆极品少妇内射AAAAAA| 婷婷激情六月中文| 91久久网站| 第五色色色婷婷| 91精产品自偷自偷综合| 婷婷六月激情| 五月丁香手机在线| 亚洲妇女熟BBW| 五月丁香六月花| 婷婷六月天| 色吧婷婷| site:hcxsz888.com| 国产欧美精品AAAAAA片| 婷婷五月色综合| 激情五月丁香六月综合AVXXXX| 亚洲色图五月丁香| 久久精品性爱视频,| 欧美性生交XXXXX无码小说| 五月丁香青草综合啪啪| 亚洲黄色av网站| 99热99干| 亚洲色五月天在线| 亚洲精品另类| 97操碰视频| 亚洲色色爱| 天天操天天插天天射| 色七七九九| 五月天婷综合网站| 伊人狼人干| 色情丁香五月婷婷精品| 六月婷婷之青青草| 伊综合蕉| 色色五月丁香| 五月天色婷婷图片| av操一操| 亚洲激情在线| 婷婷丁香激情综合色情| 久久久激情视频| 中文字幕丰满孑伦无码专区| 人人操五月天| 日韩欧美一区二区三区四区| 亚洲无码影音| 激情久久肏屄视频| 国产精品色色色色| 99热99精品| 被强行糟蹋的女人A片| 99热只有| www天天干| 国产97色在线 | 日韩| 国产一区二区三区影院| 五月丁香婷婷爱| 亚洲综合网激情五月天| 九九热精品99| 国产99久久久国产精品免费看| 欧美黄色韩日网| 丁香久色| 亭亭色网| 在线日本www| 天天爽天天日| 99色热| 热久久66| 久久曰曰| CAoub青青超碰| 欧美日韩中文国产一区发布| 91九色视频在线观看| 色五月婷婷婷婷| 五月婷婷黄色| 激情婷婷九月| 婷婷综合中文| 激情六月天| 狠狠爱婷婷爱| 九九热这里只有精品在线观看| 国产噜一噜天天噜| 欧洲一区二区| 狠狠综合久久综合| 99在线精品免费视频| 久草大| 丁香五月欧美| 五月婷婷开心综合| 亚色网站小视频| 欧美六月| 六月丁香停| 久久婷婷大香蕉| 丁香五月天成人| 丁香九月婷婷| 欧美成人A片AAA片在线播放| www.99热在线| 开心五月婷婷婷美女| 99爱免费在线视频| 怡红院院在线导航网| 91精品久久久久久77777| 美欧成人视频| 亚洲视频另类| 狼人伊人天堂| 国产麻豆视频| 亚洲亚洲人成综合网络| 丁香久久| 99色在线观看| 婷婷五月色播| 五月婷婷AV| 99精品一二三四视频| 人人摸人人| 婷婷五月天精品| 丁香六月亭亭久久综合| 色五月婷婷天天操夜夜操| 天天操天天爽天天爱| 婷婷八月激情| 99热最新精品| 丁香五月天在线视频| 99久久综合| 丁香五月婷婷久久综合激情网| 久婷婷| 啊V视频在线观看| 99久久综合网| 午夜丁香婷婷| 五月开心婷婷中文字幕| 日本激情ⅩXX免费视频| 色波激情五月天| 欧美群妇大交乱婬网| 天天激情综合| 六月婷五月丁香| 色人五月婷婷| 丁香五月婷婷激情123| 操熟女成人网| 五月天另类视频| 99久久精品国产色欲| AV在线观看网站| 色欲色香综合网| 婷婷久久综合久| 国产欧美日韩综合精品一区二区 | 久久婷婷综合国产| 亚洲成人在线免费| 99国产er热视频| 五月天成人伊人| 五月丁香六月婷婷婷婷| 色五月综合在线| 五月综合丁香婷婷| 婷婷六月丁| 双性美人被调教到喷水A片| 婷婷激情五月呦呦| 97日本在线| 东京热免费视频| 五月丁香六月婷婷在线小说视频| 色情久久久| 婷婷五月天久久| 亚洲综合在线视频| 亚洲A片成人无码久久精品青桔| 在线精品97| 日韩av在线免费观看| 综合五月丁香久久| 色狠狠综合| 大香线蕉伊人| 激情五月天色色| 任你弄在线视频免费| 丁香久久久| 色五月婷婷天天干| 丁香五月婷在线观看| 91丨九色丨白浆秘| 精品亚洲国产成AV人片传媒| 91色欲综合| 超碰在线人妻| 99热这里只有国产精品| 激情综合网激情五月天| 97色婷婷| 在线99精品| 九九这里有精品视频| 五月天久久91| 婷色五月| 久久影视婷婷五月| 91艹人| 九九色中文| 五月婷婷丁香色播网| 日韩欧美颜射| 久久99人人| 超碰在线看| 久久少妇视频| www.夜夜| 伊人五月天97| 天天综合色综合| 九九热99视频| 色色五月天 亚洲| 久热99| 天天天干夜夜夜操| 亚洲精品久久久久AV无码| 99热这里有精品首页10| 26uuu国产精品| 99久.| www.九九婷婷| 欧美激情xxxXX| 久99久在线| 99久高清视频| 深爱激情网婷婷| 日韩一级片| 五月婷婷色白丝| 热99久久这里只有精品| 色五月激情综合网| 超热久碰.com| 丁香六月天色婷婷| 五月天激情网图片| 久久婷婷国产| 五月六月伦理| 深夜婷婷 丁香| 玖月婷婷爱丁香| 大香蕉啪啪| 91丁香婷婷综合资源| 婷婷丁香五月天亚洲| 色婷视频| 丁香综合网| 亚洲乱码w在线观看| 色九九九综合| 去干网最新版本亚洲版| 久久草大香蕉| 久操婷婷| 开心五月综合激情网| 色婷婷啪啪| 九九亚洲视频| 草草色情综合网| 色婷婷在线视频久| 能看的AV| 激情综合五月婷| 91一起操| 久热中文字幕| 玖玖99免费视频| 五月婷婷色啪| 五月天婷婷成人| 久久九九99.www| 人妻自慰高清合集| 五月停性愛| 99爱免费在线视频| 无码少妇高潮喷水A片免费| 99久久国产成人精品| 中文字幕在线日亚洲9| 激情五月天婷婷图| 五月花激情| 女人露出p毛视频www网站| 婷婷婷婷色| 啪啪色激情五月天| 五月婷丁香| 五月天综合缴情网网站0| 丁香婷婷社区| 五月丁香婷婷在线综合蜜桃| 亚洲无码99| 亚洲 日韩色色| 双性美人被调教到喷水A片| 婷婷色天香| 国产成人综合电影| 婷婷五月天六点丁香五月| 人妻激情网| www,色婷婷|