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.狠狠操.co m| 婷婷狠狠色| 超碰免费成人| 激情综合网五月丁香| 色婷婷五月综合| 五月天色婷婷激情综合| 99 福利 导航| 日日操天堂| 五月丁香婷婷综合| 精品九九视频| 日本97在线观看| 丁香 久久| 五月天另类小说久久小说网| 欧美色色色| 天天碰天天插天天操| 九九色黄色| 97五月久久丁香婷婷| 亚洲国产精品五月天| 99视频热99| 91九色精品女同系列| 99热久久这里只有精品| 天天骑日日爽| 五月丁香无码| 狠狠色丁香久久综合婷婷亚洲成人福利| 九色无码| 亚洲精品午夜国产va久久成人| 色婷婷88| 超碰成人av| 国产69久久久欧美黑人A片| 丝袜激情网| 激情五月婷婷综合视频| 另类色网| 丁香六月天婷婷在线| 成人一区在线观看| 视频一区二区在线| 婷婷碰碰| 激情五月婷婷综合网| www.henhengan| 这里只有精品免费在线视频| 婷婷综合久久综合| 97婷婷五月丁香| 性一交一乱一交A片久| 丁香婷婷六月天| 香蕉AV777XXX色综合一区| 天天搞夜夜叫| 二人电影免费版在线观看| 婷婷午夜综合| 五月丁香六月香香蕉| 丁香五月天影院| 天天日天天插| 成人国产欧美大片一区| 五月开心网| 久久HD| 久色欧美| 五月婷婷激情中文字幕| 超碰97免费在线| 五月丁香在线看| 午夜丁香六月婷| 欧美激情丁香五月| 五月丁香六月婷婷在线小说视频| 婷色成人| 啄木鸟丝袜美女福利视频| 五月社区婷婷激情| 天天爽天天摸| 婷婷成年人免费视频| 另类视频丁香五月| 婷婷色操| 色色A| 婷久久| 久热欧美| 色色日韩网| 日韩啪| 精品99视频| 人人操人人添人人摸97| 婷婷综合97| 日本天堂爱爱| 亚洲精品网站色视频| 丁香五月天无码AV| 99精品22| 久/久精品99看9| 五月丁香综合激情网| 婷婷中文字幕| 五月天综合在线网| 97热久久五月婷婷| 婷婷欧美色| 激情深爱婷婷网| 亚洲色婷婷色| 婷婷综合五月色播| 亚洲综合1024| 久久艹 五月天| 婷婷色色欧美综合网| aaa久久久| 久婷狼色诱惑在线| 五月丁香激| 五月丁香六月婷婷啪啪| 操日本人妻视频| 五月花综合视频| 久久99热这里只有精品| 狠狠操狠狠插| 精品动漫 无码av| 六月婷在线| 婷婷黄色| 97丁香五月天| 久久婷婷操| xx色综合| 欧美色宗和激情| 丁香五月在线| 天堂五月婷婷| 午夜丁香六月婷| 逼里香不卡| 91碰视频| 色吊丝av中文字幕| 密乳视频| 99热这里都是精品| 青青草原伊人网| 五月婷婷高清| w婷婷五月婷婷w| 亚洲综合婷婷| 99热老网站| 五月婷婷久久内射| 九九这里只有精品| 色婷婷88| 五月丁香六月综合基地| 激情深爱五月天| 黄色高清无码| 婷婷丁香高潮了| 亚洲美女网Va| 丁香狠狠干| 亚洲天堂啪啪| 久久99热这里只有精品| 五月Huangsewang| 久久婷婷五月天激情| 婷婷四色五月| 久久久久婷| 天天色亚洲| 久婷婷久草| 人人草成人视频| av性爱网站| 国产成人网| 精品一区二区三区三区| 激情小说视频图片网| 九九热最新地址| 激情婷婷网| 狠色狠色狠色狠色狠色网| 成人在线99| 久色视频| 久久99网站| 这里只有免费精品| 日本在线观看aaa 99| 五月婷婷综合久久| 我要射综合| 9l视频自拍9l视频自拍九色学生| 色婷婷精| 天天天天天久久久久久| 久9热插入| 六月丁香深深爱| 色五月在线播放| www色综合亚洲92| 欧美性爱5月天天天看| 婷婷色网| Av性爱网| 欧美性生交XXXXX无码小说| 成人网址在线观看| www.99久久久久99| 丁香五月影院| 99色干| 五月色欧洲| 婷婷五月天色色| 亚洲无码另类| 这里只有精品视频| 天天操夜夜肏| 国产精产国品一二三在观看| 六月丁香婷婷六月激情综合| 亚洲精品国产成人AV在线| 综合网啪| av网址在线| 久久五月情| 99热在线观看免费| 五月丁香亭亭操逼| 丁香五月综合| 99热中国| 99精品久久久久久久| 99爱视频免费| 久久国产一区二区三区| 深爱激情网五月天| 色色色区| 五月激情小说| 五月天色社区| 五月丁香日本一抹本| 色婷婷狠狠18禁| Av狠狠色丁香婷| 97精品人人A片免费看| 开心五月婷婷激情| 成人做爰A片免费看视频| 千人斩操逼| 超碰免费人| 丁香欧美| 91打屁股视频网站| 国产日韩欧美| 五月婷婷九九热| 久久多色| 日韩成人精品中文字幕电影| 99久久久久久www| 99在线观看| 丁香六月啪啪| 类似婷婷激情综合网站| 五月天小说激情| 青青草国产亚洲精品久久| 伊人超碰在线| 思思热这里只有精品| 99网址在线看| 亚洲婷婷性爱| 五月伊人网| 丁香五月六月久久综合| 色色婷婷婷丁香五月天| 狠狠色五月天| 久久这里在精品视频| 综合五月天| www婷婷色情网| 超碰成人影视| 色色国产| 丁香五月另类色婷婷麻豆| 激情综合网五月天天| 丁香五月 性爱| 色婷婷基地| 热久久91| 婷婷之玖玖| 91精品综合久久久久久五月丁香| 亚洲综合五月| 99亚洲色| 天天激情综合| 色综合久久无码| 天干夜夜操| 这里只有精品视频99| 啪啪婷婷五月天激情| 九七色色六月丁香| 天天插综合| 亚洲色五月婷婷| 色色色99韩| 丁香六月婷婷基地| 久久97| 丁香六月五月婷婷| 久久精品永久免费| 五月婷婷干干干| 国产亚洲色婷婷久久99精品9j| 五月婷婷视频| 日韩AAAAA| 免费精品66| 婷婷五月激情在线| 一区二区三区四日本| 99啪啪| 美女91一起草| 久久丁香九| 婷婷.com| 热九九精品| 欧美日比视频| 日日夜夜干| 99爱在线| 狠狠色狠狠色综合日日91| www狠狠| 丁香婷婷色情社区成人小说| 五月丁香六月婷婷综合网缴情| 深爱丁香网| 久久人五月| 国产三级在线播放| 92久操视频| 夜夜嗨一区二区三区直播内容| 天天色天天日| 激情六月天| 狠狠狠狠狠| 天天色综网| 亚洲啪啪视频| 狠狠草在线观看| 五月天婷婷基地| 99久久极情精品一区| 婷婷五月天激情五月天| 久久婷婷五月免费视频| 伊人久久大香线蕉av最新| 午夜成人天堂久久无码日韩久久| 激情婷婷六月天| 五月丁香啪啪啪| 精品亚洲国产成AV人片传媒| 操逼视频网址| 色五月首页| 超碰免费人妻| 五月丁香婷色| 婷婷丁香五月高清| 狼人狠狠操| 99无码精品| 超碰在线观看9| 激情爱爱网站| 丁香五月综合| 婷婷开心五月| 色综合激情| 26uuu精品一区二区| 超碰99在线| 玖玖91| 91疯狂操操操操| 九九99免费视频| 婷五月丁香| 五月天天天色| 精品无码久久久久久久久| 99热10在线高清播放| 天天插天天射天天干| 18av天堂| 七七色色综合| 在线观看日韩12345区| 男人天堂AV在线一区二区| 色色丁香| 丁香五月天婷婷中文字幕| 99色热| 亚洲黄色网址| 天天搽天天射| 国産精品| 在线看av| 思思热国产在线| 啊v视频在线观看| 综合久久激情久久| 激情久久四色| 99操逼| 丁香五月熟女| 色婷婷五月天天天做| 五月天综合| 亚洲V国产V欧美V久久久久久| 成人网站高清无码| 天天天天做夜夜夜夜做| 99国产精品久久久久久久久久久| 99操中文视频| 婷婷操超碰| 91人妻人人操| 五月丁香六月合| 翔田千里 50岁 无码| 精品日本视频444| 丁香五月天在线视频| 五月丁香在线| 爆乳熟女一区二区三区爆乳| 综合色五月| 国产精产国品一二三在观看| 激情久久四色| 色色99| 免费啪啪亚州视频| 婷婷久久精品| 久久婷婷人人| 久久久婷婷五月亚洲97号色| 日韩免费99| 99热在线观看亚洲区| 五月婷婷六月丁香| 青青操avbb| 五月天另类小说| 91精产一区三区免费观看| 中文网av| 婷婷丁香红五月91C| 美女丁香五月天| 五月婷婷色色色| 婷婷丁香五月天影院 | 色停停五月天| 韩国97天堂| 色情激情五月| 中文字幕91,综合| 九九99久久| 日噜噜色| 色综合五月天| www狠狠| 午夜激情婷婷| 九九性视频| 五月丁香啪啪激情| 综合激情伊人影视在线| 五月天激情小说| 亚洲激情99| 国产一区二区三区影院| 久热这里只有精品66| 人人色人人弄人人操| www..com色爱| 婷婷五月综合色小姐小说| 色5月婷婷| 丁香五月大香蕉在线99| 婷婷婷婷婷开心无码播放| 亚洲国产黄色电影| 91热99| 中文字幕综合网| 超碰在线视屏| 色婷婷基地 | 欧美丁香六月激情视频| 在线免费观看激情视频| 日韩狠狠色| 色色激情| 影音 五月 婷婷 久久| 99亚洲无码| 伊人碰碰婷婷| 中文字幕人成乱码在线观看| 骚。com| 538任你爽视频不一样的| 无码色| 激情综合亚洲| 26uuu色五月| 九九热最新| 色婷婷九月| 嫩草AV久久伊人妇女超级A| 激情丁香五月婷婷啪啪| www.99久久久| 久久久精品免费啪啪国| 91操网| 色五月aV| 91人人网| 日本天堂网站99| 婷婷久久五月天丁香| 五月婷丁香| 婷婷五月欧美综合| 99热最新| 色婷婷小说| 91一起操| 激情综合婷婷久久| 青草视频在线观看视频| 人人综合久| hd五月婷婷在线| 久久天堂婷婷五月| 一本色道久久88加勒比| 91九色首页| 婷婷五月色丁香在线看| 成人五月丁香社区| 月丁香久久久| 国产精品人成A片一区二区| 国产午夜一区二区三区| 丁香六月婷婷高清| 色婷婷手机在线| 久久天堂女人| 99精品国产乱码久久久人妻| 激情文学久久| 激情五月色婷婷| 久久婷婷亚洲五月天| 五月天婷婷影院| 影音先锋男人AV资源站| 极品少妇XXXX精品少妇偷拍| 九九热视频这里只有精品| 婷婷网五月天| 婷婷五月天激情基地| 亚洲婷婷五月天综合| 综合色色综合| 9色免费网| 香蕉AV777XXX色综合一区| 超碰在线视屏| 99九九99九九九视频精彩| 五月婷婷狠狠干| 久久视频这里都是精品| 天天爽在线视频| 啪啪黄页网| 九九激情| 99热在线看| 五月天婷婷色播综合在线| 久久五月综合| 成人 在线 日韩| 免费视频99| 五月丁香无码视频| 99热国产在线| 99视频这里只有精品10| 亚洲色情在线| 狠狠色综合网站久久久久| 手机看片日日做夜夜| 女性自慰系列第五页| 黄色五月婷婷| 色九月婷婷| aa久久| www.久久爱.com| AV在线收看| 婷婷五月超碰| 欧美乱码国产一级A片| www.91AV.COM| 五月丁香六月成人| 99精品久久久久久久婷婷| 99热丁香| 欧美色图45678| 婷婷在线视频| 丁香五月六月久久综合| 丁香色啪综合| 欧美激情凹凸丁香网| www.26uuu.com亚洲电影| 六月五月婷婷| 婷婷婷婷婷婷婷婷| 五月天激情四射| 大香蕉婷婷五月天| 99自拍视频| 欧美激情综合色综合啪啪五月| 人妻久久久久久| 极品人妻VIDEOSSS人妻| 色五月激情图片| 碰超在线九色| 婷婷永久在线| 91啪级电影| 婷婷五月丁香久久| www,色婷婷| 五月丁香六月激情在线| 激情五月丁香五月色| 91九色超碰| 色色影院黄大片| 色婷婷啪啪啪啪啪啪| 久久99久久99精品免观看粉| 色黑鬼导航| 99热精品一| 另类激情首页| 五月激情天| www,奇米影视| 久久永久视频| 精品九九视频| 婷婷综合97| 天天干天天干天天干| 日本不卡高字幕在线2019| 五月停亭久久电影| 五月开心婷婷极品激情| www,av好吊操| 色欲色香综合网| 久久AV无码精品人妻系列试探| 国产超碰av| 久热综合| 亚洲色情网站| 丁香五月综合| 中文av在线观看| 色五月婷婷婷婷婷婷婷婷婷婷 | 亚洲欧美另类在线23p| 久久与婷婷| 99精品国产在热久久| 六月婷婷AV| 天天弄天天爽| 九九99九九99| 亚洲国产黄色电影| 色噜噜狠狠色综合日日免费| 思思热久久艹| 9色免费网| 六月婷婷五月丁香首页| 在线中文亚洲| 人人操婷婷| Xx色综合| 日韩无码专区| 婷婷成人在线| 色五月视频,小说| 婷婷五月色播放| 91 久热| 久久久久婷婷五月热综合| 五月婷婷综合在线| 变天就操逼婷婷五月| 新99思思视频| 激情綜合W W W,激情五月天| 激情99| 色婷婷社区| 亚洲亚洲人成综合网络| 亚洲VA欧美VA| 精品久久艹| 色婷婷色九月| 激情亭亭五月| 丁香九月综合在线| 久久A V无码视频| 青青久在线视频免费观看| 精品成人在线观看| 成人五月天丁香婷| 美女精品一级不卡视频| www.9797国产| 欧美激情中文字幕| 五月激情天| 久久婷婷艹| 少妇口诉沐足视频播放器网址| 可以直接看的AV| 超碰色色综合| 久综合| 色色综合激情| 偷拍91九色| 五月丁香久久色| 亚洲六月色| 日本偷拍九九九| 欧美综合五月丁香五月天| 丁香六月婷婷久久综合| 色五月久久成人婷婷| 久久思思热| 婷婷五月天最新综合你懂的 | 9 1超碰九色| 精品女人九九九| 欧洲S级在线观看| 九九性爱网| 人人操人人爽成人AV| 九九婷婷网五月天| 手机在线日韩视频中文字幕| 五月丁香婷婷综合久久| 色婷婷丁香五月天| 亚洲激情av| 色五月婷婷少妇人妻| 99热在线观看| 久久九精品| 久草婷| 深爱激情五月网| 一婬一伦一区二区三区| 激情五月开心五月在线视频| 婷婷五月天在线观看| 激情婷婷内射| 色青青电影色五月| 99热在线观看免费精品| 亚洲国产成人在线| 女人高潮内射99精品| 色宗合久久五月婷婷| 97超级啪啪在线观看| 亚洲综合色色| 色狠狠综合| 99国产精品久久久久久久久久久| 激情五月天色婷婷综合| 狠狠干无码| 高清激情av在线观看| 色五月婷婷在线观看第一页舔| 色五月婷婷色五月| 天天摸天天肏| 大香蕉在九| 六月天婷婷| 日本久久精品| yirenjiqingshiping| 成人视频在线免费播放| 梁铮版蜘蛛女在线观看| 丁香六月欧美| 五月婷在线| 99热久草| 婷婷月五天在线在线看| 九九久久腿| 91五月天| 激情欧美五月丁香| 久久网站免费亚洲| 99色视| 99精品久久| 色狠狠综合入口| 亚洲国产婷婷色五月| www.五月丁香| 日韩无码一区二区三区四区| 狠狠色丁香婷婷五月| 亚洲超碰在线| 国产精品爽爽久久久久久| 五月婷婷五月天激情视频| 操操操91| 一本色综合色| 狠狠狠狠狠| 六月激情久久| 小视频一区| 色情五月综合婷婷| 久久网婷婷| 成人美女网| 第四色激情网| 夜夜干夜夜操| WWW.99热| 丁香婷五月天| site:hcxsz888.com| 婷婷五月天AV在| 婷婷五月激情黄色| 欧美大肥婆大肥BBBBB| 欧美三日本三级少妇三99| 久久AV电影| 99re这里只有精品国产99| 国产九九一区二区三区| 伊人成综合五月婷婷| 丰满少妇猛烈A片免费看观看| 五月天综合网| 激情综合网五月激情| 人妻videos人妻高清| 五月丁香大香蕉| www.久久综合| 超碰成人免费| 香蕉婷婷色五月| 激情综合色播| 色噜噜狠狠插综合| 天天色天天色天天色天天色天天色| ay2区| 久热9| 97碰| 久久网日本| 99热1| 久久婷婷人人| 久久99综合网| 9l视频自拍9l视频自拍九色学生| 97艹| 丁香五月开心亚洲| 69久久99精品久久久久| 午夜九九九九九九九九九九九九九| 激情碰碰碰| 俺去婷婷 丁香| www.久操| 五月激情综合性爱| wWW九九在线播放| 激情久久 婷婷| 亚洲成人无码网站| 99在线播放视频| 香蕉综合在线| 亚洲 综合中文| 五月天色狠狠| 婷婷深爱五月亚洲综合| 国际国外精品欧洲南美洲专区无码不卡| 狠狠擼综合| 午夜精品777| 中文字幕久久一区二区三区| 五月婷婷亚洲| 婷婷操逼| 婷婷永久在线| 丁香五月婷婷色偷偷| 色五月婷婷影院| 新激情五月天天在线网| 久久综合爱| 色播丁香| 在线日本www| 97人人爱人人操| 超碰成人电影| 五月婷婷co.m| www夜夜| 激情婷婷丁香五月天| 天天操婷婷| 免费在线观看AV网站| 九久热| 91黄址| 婷婷大美在线| 99爱视频在线观看这里只有精品| 欧美成人精品A片免费一区99| 婷婷六月激情小说网| 婷婷久久国产视频| 99A片| 特黄三级片| 九九这里只有精品| 91色欲综合| 99亚洲天堂| 色青五月天| 99久精品视频| 国产精品涩涩涩视频网站| 丁香五月婷婷激情蜜桃| 五月激情视频| 日日夜夜小色哥| 丁香五月香蕉| 91九色白丝| www.婷婷五月天.com| 热91久| 九九热精品99| 婷婷丁香五月欧美人| 99人妻碰碰碰久久久久视| 另类在线| 九热久| 日批在线看| 秋霞A V毛片| www五月婷婷88导航| 中文字幕综合| 丁香5月婷婷| 激情综合网五月激情| 99九九热播在线免费视频| 久久黄A片| 天天激情欧美美女| www.色五月| 久婷| 天天干,天天日| AAA级久久久精品| 人妻熟妇国产精品| 人人干av| 91在线视频观看午夜福利| 婷婷激情小说网| 免费AV在线| 五月丁香亚州综合网| 色婷婷五月六月丁香综合视频| 五月天婷婷7米| 新激情婷婷| 99热精品在线播放观看| 色五月综合网| 91青娱乐青青草| 丁香五月婷综合网| 日本女色人人| 五月丁香天天| 婷婷综合五月| 国产一级片| 五月丁香久久网| 9999三级片| 色噜久| 五月天国产婷婷精品视频在线| 国自产拍偷拍精品啪啪一区二区| 激情网站五月| 天天干天天干天天干天天干天天干| 国产成人AV在线播放| 狠狠干综合网| 久久婷婷大香蕉| 色五月丁香伊人| 黄网在线免费| 五月天激情日色在线| 成人免费120分钟啪啪| 五月婷婷丁香啪啪| 五月婷婷久久综合| 婷激情五月天视频导航| 欧美成人精品A片免费一区99| 丁香六月啪啪啪| √天堂资源在线人妻熟女| 天天操五月天| 玖玖婷婷色五月| 五月婷婷深深爱| 人人妻人人澡| 91Chinese在线| 五月天色社区| 激情五月天婷婷久久久久久久久久久| 五月天婷婷久久视频| 久操婷婷| 亚洲精品亚洲人成人网| 蜜臀A∨在线水帘洞| 五月天激情婷婷| www.狠狠操.con| 天天碰夜夜操| 婷婷五月视频| 五月丁香毛片| 色噜噜婷婷| 色五月丁香总合网| 思思热精品在线| 午夜丁香六月婷| 丁香激情网| 久久五月天激情美女| 99热免费| 丁香五月开心婷婷| 在线观看亚洲AV| 久久99视频| 色五月婷婷少妇人妻| 激情98色婷婷五| 色五月AV| 国产激情综合| 疯狂做受XXXX高潮A片| 五月天激情av| 翔田千里 50岁 无码| 五月婷婷丁香五月| 99亚洲色| 在线另类视频| 97碰碰碰免费公开在线视频| 丁香五月婷综合网| 久操热线| 国产毛片操B| 另类精品视频在线观看| 五月天婷婷自拍图片在线观看| 久久久高清| 热五月婷婷| 五月天婷婷丁香花| 4399伦理午夜| 乱岳熟女50岁| 综合伊人久久| 99热在线中文字幕| 久久五月天色婷婷| 国产亚洲精品久久久久苍井松 | 无码免费人妻A片AAA毛片西瓜| 丁香五月五月婷婷五月天激情四射| 久久综合色五月| 另类少妇人与禽zOZZ0性伦| 日日夜夜久| 久久最新色色色| 丁香青青五月天| 综合色五月天| 久久色9| 国产成人精品一区二三区熟女在线| 欧美VA在线| 色婷婷91激情小说| 丁香五月婷婷亚洲另类| 噼里啪啦完整版中文在线观看| se99视频| 丁香五月成人论坛| 丁香婷婷色色| 五月丁香六月综合图| 91精品91久久久中77777| 亚洲亚洲亚洲AAAAAA| 婷婷的激情五月| 天天插天天射天天干| 五月天操逼激情| 99这里只有| 五月婷婷婷丁香播| 五月婷婷深爱六月| 五月花综合网| 色六月婷婷| 九九精品婷| 日本一级淫| 五月婷婷综合在线| 婷婷五月综合社区| 亚洲a色| 久久一二三视频| eeuus五月婷| 色五月超碰| 伊人影院久久网| 丁香五月婷婷国产av| 99热啪啪| 天天日,天天干,天天操| 五月天婷婷AV| 26uuu成人网| 五月丁香婷爱在线| 日日夜夜爽爽| 五月欧美色色五月| 五月丁香少妇网| 就要去操亚洲成人精品五月天丁香婷婷| 五夜丁香| 黄网在线播放| 亚洲在线操| 久久98热re| 激情综合五| 五月开心激情| www.五月.com| 狠狠色综合精品视频在线| 武汉美女啪啪视频免费一级片| 婷婷六月爽| 思思热久在线观看视频| 丁香六月婷婷开心| 日日夜夜狠狠婷婷色| 毛片网站谁有| 亚洲激情无码久久| 久1色色| 在线VA视频| 午夜 外网 精品 在线| 丁香婷婷激情五月色| 婷婷五月天成人动漫| 精品九九在线观看| www.五月天婷婷姐姐| 激情五月丁香在线观看直播| 思99热精品久久只有精品| 婷婷五月天99| 五月好婷婷| 五月婷婷婷| 色色色五月婷| 成人在线日韩| 婷婷五月天激情小说| 香蕉AV福利精品导航| 中字幕视频在线永久在线观看免费 | 国产Va视频| 99久久综合网| 五月激情久久综合网| xx人人xx| 色综合区| www.夜夜操| 五月婷婷丁香日韩在线| 五月丁香六月婷婷激情四射| 狠狠99| 中文字幕丰满孑伦无码专区| 五月天婷婷色播综合在线| 在线sebiav精品视频| 我去色色网五雨天| 玖玖婷婷五月天| 天天婷婷天天| 亚洲视色| 丁香五月天啪啪| 无码AV免费精品一区二区三区 | 99碰| 激情五月天激情网| 激情九九这里只有精品| 婷婷五月天狠狠色| 色情五月综合婷婷| 97综合视频在线| 操操自拍| 97久久香草精品视频| 五月天婷婷在线AN| 亚洲免费看片| 激情九月丁香婷婷| 婷婷丁香九月| 亚洲 无码 中文字幕 中出| 丁香六月成人| 五月天桃色深爱网| 亚洲成人丁香花| 日韩欧洲亚洲| 一级A片天天操夜夜操| 神马欧美精| 日本欧美成人片AAAA| 五月亭久久无码视频| 天天舔天天插天天爱| 天天婷婷色六月| 色色色色热| 9 9热这里有精品| 欧美五月丁香在线| 丁香六月五月天| 337p大胆噜噜噜噜噜91Av| 久re在线| 五月婷婷久久激情| 色色色五月婷| 伊人九热| 国产噜一噜天天噜| 日日干夜夜干| 婷婷五月丁香亚洲| 97人人干| 99热综合| 亚洲无码 图片区| 婷婷在线视频| 日本三级日本三级99| 天堂婷婷丁香六月网| 97热视频| 亚洲免费在线观看岛国| 99久久成人| 五月婷在线观看| 久婷久婷激情肉| 思思热99在线| 女人天堂AV| 区美毛片子| 婷婷五月天激情基地| 99色在线| 久久九九99| 9热在线观看| 午夜激情久久| 26UUU精品一区二区Com| 天天色天天操天天射| 国产亚洲网站在线| 人人草人| 日韩五月婷婷久久| 亚洲综合网激情小说| 玖玖热视频| 8区视频在线| 婷婷八月丁香激情综合| 超级碰碰一区| 99青青草| 草草色情综合网| 亚洲五月天伊人| 国产精品电影| 日韩三级片一区二区| 久草婷婷| 丁香婷婷五月综合色情| 日韩在线视频中文字幕| 97碰碰碰| 丁香五月天激情综合| 奇米影视777在线_在线观看午夜_h小视频在线观看_岛国大片 | 麻豆科斗777| 欧美激情VA永久在线播放| 婷色五月天| 丁香六月激情四射| 婷婷网影院| 色欲久久久久久综合网综合网| 久久99久久久久久久噜噜| 99精品免费欧美小视频 | 97超级碰人人| 五月丁婷婷| 春色激情| 日日艹思思热| 久久青草国| 婷婷五月天播播| 色情开心五月| 激情综合在线观看| 婷婷丁香五另类网站| 四色永久成人网站| 丁香五月婷婷深五月| 九九综合色| 五月丁香成人| 久久婷婷一级片| 99er精品视频| 国内久久亭亭| 色综合网址| 丁香婷婷人妻| 无码人妻AV久久久一区二区三区| WwW天天干| 狠狠色婷| 超碰99热精品| 五月综合久久| A片试看50分钟做受视频| 五月天婷婷色小说| 去色色五月天| 99ri国产在线| 国产色色网站网址| 五月久久丁香| 色婷婷综合网| 久久香蕉网| 成人国产欧美大片一区| 国产成人99久久亚洲综合精品| 久热丁香| 五月天丁香网| 久久机热这里只有精品| 狠狠情色| 综合网色| 婷婷色五月综合| 日本婷久久| 五月综合激情| 欧美综合激情丁香五月六月婷| 色吧五月婷婷| 五月婷在线| 狠狠xx| www.激情.com.| 亚洲成AV人片在线观看| 国产97色在线| 久久这里都是精品视频| 久久亚洲天堂| 欧美在线视频99| 久久99热久久99精品| aⅤ79成人片| 综合一区二区三区| 丁香五月色综合色播五月| 欧美日韩国产成人在线| 欧美日韩成人| 色婷婷综合网站| 伊人99热| 一本狠婷婷综合| 综合色播| 五月丁香六月婷婷无码| 俺也去婷婷五月天第五色| 另类国产欧美视频| 大香蕉520| 四月婷婷五月丁香| 熟女五月天久久综合| 日韩人妻无码精品| 五月桃花网综合| 九九99精品视频在线观看| 午夜丁香五月天综合| 可以免费观看的av网址| 丁香香蕉婷婷| 无码人妻AV久久久一区二区三区 | 久久婷婷六月综合| 五月婷六月| 五月天天天开心激情网| 99在线精品视频| 婷婷五月综合色小姐小说| 久99久视频| 色情五月天丁香社区| 婷婷开心激情综合五月天| 91丨九色丨熟女高潮| 2013AV天堂| 七月丁香婷婷 色色| 激情小说五月天| 任你日视频| 26uuu最新地址| 热久久视频99| 99激情视频热| 激情小说五月天| 99热日| 99久高清视频| aaaa久久| 亚洲精品一区中文字幕乱码| 99这里只有精品视频| 99热免费精品| 久久精彩视频| 久草五月天| 日韩操逼小电影| 我爱婷婷五月天综合88| 成人天天爽| 五月丁香婷婷综合| 激情综合在线观看| 影音先锋 一区| CAOBIBI| 影音先锋AV男人站| 99在线资源视频| 狠狠婷婷色| 六月成人网| 亚洲字幕AV一区二区三区四区| 色播播五月天| 天天玩夜夜操| 九九热最新视频| 婷婷六月丁香五月| 亚洲在线激情婷婷五月| 久热这里只有国产| 色很很96| 婷婷五月激情的图片| 蜜臀丁香黄色婷婷五月天| 五月色网| 久久综合丁香五月| 五月天色播网| 五月天·www·com| 久久久久综合激动五月天| a69在线视频| 少妇婷婷五月天| 99热在线这里只有精品| 婷婷五月天亚洲精品| 久久机热思思热| 亚洲情欲| 丁香五月开心亚洲| 9热视频在线观看| 六月 丁香 视频| 久久久com| 久久在线视频免费观看| 久久精品A片777777| 五月Huangsewang| 婷婷综合玖玖五月| 免费成人中文字幕| 国产综合婷婷| 婷色五月| 立川无码av| 激情小说之五月| 丁香五月天啪啪| 激情另类综合| 激情AV| 色综合久久久综合久久网| 艹色18p| 97碰碰视频在线观看免费| 99免费热在线精品| 五月天久久成人| 五月婷在线视频免费看| 色婷婷五月天成人网| 开心五月网| 又大又粗九一在线| 久啪欧美| 久久机热这里只有精品免费视频| 丁香婷婷五月天色播| 曰日爽日日操| 成人短视频在线| 亚洲欧洲中文日韩久久AV乱码| 婷婷丁香大香蕉| 九九这里是免费的视频5| 久久婷婷五月天蜜桃| 九九久久综合网站| 久久婷婷热| 久er7久热| 婷婷噜噜| 大香蕉综合网| 大香伊人久色| 成年人夜夜喷水| 日韩av干| 无码髙清| 久久er99热精品一区二区| 日本 色综合| 都市激情久久| 婷婷色5月激情网| 97干在线| a免费在线| 中文字幕成人| 激情五月天色婷婷| 丁香六月五月天| 婷婷五月天大香蕉在线视频观看| 大香蕉婷婷五月天| 66精品成人免费网站在线观看| 免费啪啪亚州视频| 91色呦哟| 九九99精品视频在线观看| 五月天婷网| 五月天激情小说| 久久婷婷五月激情综合| 99热这是里只有精品| 丁香五月中文字幕色播| 亚洲亚洲人成综合网络| 99a级片| 日本激情五月天‘| 天天插天天射| 丁乡久久| 国产精品久久7777777精品无码| 五月天综合网| 亚洲一级AV在线免费播放| 五月天婷婷开心| 九九热这里| 天堂五月婷婷| 综合网五月天123| 五月婷在线| 色婷婷69| 丁香五月婷久久| 艳妇野外情欲放荡HD| 久热九九| 九色无码| 国产三级在线播放| 天天摸天天舔天天爽| 操碰99| www91久久| 这里只有精品免费观看网占| 99国产精品久久久久久久久久久| 一区二区成人电影| 亚洲无码99| 99九九99九九九视频精品| 激情五月婷婷伊人| 激情四射五月天| 色色激情| 婷婷成人综合| 久色五月天| 99热这里只有精品2| 亚洲精品a成人在线播放| 免费的日逼视频| 五月激情影视| 婷婷久久五月| 久久久.COM| 天天操天天曰天天射| 日本婷婷色日| 亚洲韩国日产综合AV| 色综合综合网| 操操综合网婷婷| 开心激情久久久久久久| 国产古装妇女野外A片| 夜夜躁狠狠 | 人人爽天天爽| 亚洲区,视频区,视频区免费| 超碰色色综合| 五月婷婷色影院| 欧洲不卡视频| 人人操AV| a在线观看| 欧美性二区| 99操逼| 婷婷丁香第一页| 狠狠色 综合色区|