[{"data":1,"prerenderedAt":3360},["ShallowReactive",2],{"page-\u002Fcsharp\u002Fwpf\u002Fhandycontrol\u002Fthemes":3},{"id":4,"title":5,"body":6,"description":33,"extension":3354,"meta":3355,"navigation":49,"path":3356,"seo":3357,"stem":3358,"__hash__":3359},"content\u002Fcsharp\u002FWPF\u002FHandyControl\u002FThemes.md","Themes",{"type":7,"value":8,"toc":3330},"minimark",[9,14,27,122,125,156,159,187,190,227,241,245,248,251,491,502,510,513,520,523,527,530,537,547,550,553,595,598,604,607,612,626,675,684,706,716,756,763,778,785,798,828,831,868,872,884,893,896,905,912,965,968,971,975,981,996,999,1028,1042,1045,1055,1093,1096,1099,1114,1131,1135,1138,1166,1173,1220,1231,1235,1238,1249,1273,1276,1283,1292,1314,1318,1331,1334,1372,1375,1379,1382,1385,1389,1392,1395,1409,1459,1462,1473,1477,1480,1544,1562,1579,1589,1593,1596,1612,1616,1622,1640,1651,1656,1668,1671,1675,1685,1688,1692,1695,1709,1713,1719,1749,1752,1755,1758,1766,1781,1793,1796,1811,1818,1838,1841,1846,1860,2006,2029,2032,2041,3263,3266,3269,3272,3282,3285,3326],[10,11,13],"h2",{"id":12},"colors","Colors",[15,16,17,18,22,23,26],"p",{},"Thems负责的是主体系统，我们点开Basic文件夹里，可以看到的是Colors、ColorsDark、ColorsViolet。\n![[Pasted image 20260402170708.png]]\n这里看名称还是比较可以清晰明了的，基本是用Light\u002FDark这样的开头来阐述，还有一个文件叫做ColorsDark，里面保存的是黑暗主题的颜色代码，这两个对比的颜色就可以任意切换颜色主题。\n而在Avalonia版本中，HandyControl使用了更现代的主题字典方式，在单个",[19,20,21],"code",{},"Colors.axaml","文件中通过",[19,24,25],{},"ResourceDictionary.ThemeDictionaries","来管理不同主题的颜色 Colors.axaml:4-96 ：",[28,29,34],"pre",{"className":30,"code":31,"language":32,"meta":33,"style":33},"language-xml shiki shiki-themes github-light github-dark","\u003CResourceDictionary.ThemeDictionaries>\n\n\u003CResourceDictionary x:Key=\"Default\">\n\n\u003C!-- 明亮主题颜色 -->\n\n\u003C\u002FResourceDictionary>\n\n\u003CResourceDictionary x:Key=\"Dark\">\n\n\u003C!-- 黑暗主题颜色 -->\n\n\u003C\u002FResourceDictionary>\n\n\u003C\u002FResourceDictionary.ThemeDictionaries>\n","xml","",[19,35,36,44,51,57,62,68,73,79,84,90,95,101,106,111,116],{"__ignoreMap":33},[37,38,41],"span",{"class":39,"line":40},"line",1,[37,42,43],{},"\u003CResourceDictionary.ThemeDictionaries>\n",[37,45,47],{"class":39,"line":46},2,[37,48,50],{"emptyLinePlaceholder":49},true,"\n",[37,52,54],{"class":39,"line":53},3,[37,55,56],{},"\u003CResourceDictionary x:Key=\"Default\">\n",[37,58,60],{"class":39,"line":59},4,[37,61,50],{"emptyLinePlaceholder":49},[37,63,65],{"class":39,"line":64},5,[37,66,67],{},"\u003C!-- 明亮主题颜色 -->\n",[37,69,71],{"class":39,"line":70},6,[37,72,50],{"emptyLinePlaceholder":49},[37,74,76],{"class":39,"line":75},7,[37,77,78],{},"\u003C\u002FResourceDictionary>\n",[37,80,82],{"class":39,"line":81},8,[37,83,50],{"emptyLinePlaceholder":49},[37,85,87],{"class":39,"line":86},9,[37,88,89],{},"\u003CResourceDictionary x:Key=\"Dark\">\n",[37,91,93],{"class":39,"line":92},10,[37,94,50],{"emptyLinePlaceholder":49},[37,96,98],{"class":39,"line":97},11,[37,99,100],{},"\u003C!-- 黑暗主题颜色 -->\n",[37,102,104],{"class":39,"line":103},12,[37,105,50],{"emptyLinePlaceholder":49},[37,107,109],{"class":39,"line":108},13,[37,110,78],{},[37,112,114],{"class":39,"line":113},14,[37,115,50],{"emptyLinePlaceholder":49},[37,117,119],{"class":39,"line":118},15,[37,120,121],{},"\u003C\u002FResourceDictionary.ThemeDictionaries>\n",[15,123,124],{},"定义的颜色资源会在Theme.xaml中被映射为各种画刷，供控件使用 Theme.xaml:838-888 。例如：",[126,127,128,139,148],"ul",{},[129,130,131,134,135,138],"li",{},[19,132,133],{},"PrimaryColor"," → ",[19,136,137],{},"PrimaryBrush","（渐变画刷）",[129,140,141,134,144,147],{},[19,142,143],{},"LightPrimaryColor",[19,145,146],{},"LightPrimaryBrush","（纯色画刷）",[129,149,150,134,153,147],{},[19,151,152],{},"DarkPrimaryColor",[19,154,155],{},"DarkPrimaryBrush",[15,157,158],{},"先不聊Theme，因为还有其他重要的文件需要阅读，以及Theme这个文件实在过于庞大，很多的任务都在这里面处理。除了颜色画刷以外，theme还处理了大量的矢量图形资源，用于图标和装饰元素 Theme.xaml:91-94",[28,160,162],{"className":30,"code":161,"language":32,"meta":33,"style":33},"\u003CGeometry o:Freeze=\"True\" x:Key=\"AllGeometry\">M 721.005 638.949...\u003C\u002FGeometry>\n\n\u003CGeometry o:Freeze=\"True\" x:Key=\"DragVerticalGeometry\">M2,12 C3.1045694,12...\u003C\u002FGeometry>\n\n\u003CGeometry o:Freeze=\"True\" x:Key=\"DropperGeometry\">M798.165333 97.834667...\u003C\u002FGeometry>\n",[19,163,164,169,173,178,182],{"__ignoreMap":33},[37,165,166],{"class":39,"line":40},[37,167,168],{},"\u003CGeometry o:Freeze=\"True\" x:Key=\"AllGeometry\">M 721.005 638.949...\u003C\u002FGeometry>\n",[37,170,171],{"class":39,"line":46},[37,172,50],{"emptyLinePlaceholder":49},[37,174,175],{"class":39,"line":53},[37,176,177],{},"\u003CGeometry o:Freeze=\"True\" x:Key=\"DragVerticalGeometry\">M2,12 C3.1045694,12...\u003C\u002FGeometry>\n",[37,179,180],{"class":39,"line":59},[37,181,50],{"emptyLinePlaceholder":49},[37,183,184],{"class":39,"line":64},[37,185,186],{},"\u003CGeometry o:Freeze=\"True\" x:Key=\"DropperGeometry\">M798.165333 97.834667...\u003C\u002FGeometry>\n",[15,188,189],{},"还有各种控件的基础样式，通用尺寸值 Theme.xaml:100-105：",[28,191,193],{"className":30,"code":192,"language":32,"meta":33,"style":33},"\u003Csystem:Double x:Key=\"DefaultControlHeight\">28\u003C\u002Fsystem:Double>\n\n\u003Csystem:Double x:Key=\"SmallControlHeight\">20\u003C\u002Fsystem:Double>\n\n\u003CThickness x:Key=\"DefaultControlPadding\">10,5\u003C\u002FThickness>\n\n\u003CCornerRadius x:Key=\"DefaultCornerRadius\">4\u003C\u002FCornerRadius>\n",[19,194,195,200,204,209,213,218,222],{"__ignoreMap":33},[37,196,197],{"class":39,"line":40},[37,198,199],{},"\u003Csystem:Double x:Key=\"DefaultControlHeight\">28\u003C\u002Fsystem:Double>\n",[37,201,202],{"class":39,"line":46},[37,203,50],{"emptyLinePlaceholder":49},[37,205,206],{"class":39,"line":53},[37,207,208],{},"\u003Csystem:Double x:Key=\"SmallControlHeight\">20\u003C\u002Fsystem:Double>\n",[37,210,211],{"class":39,"line":59},[37,212,50],{"emptyLinePlaceholder":49},[37,214,215],{"class":39,"line":64},[37,216,217],{},"\u003CThickness x:Key=\"DefaultControlPadding\">10,5\u003C\u002FThickness>\n",[37,219,220],{"class":39,"line":70},[37,221,50],{"emptyLinePlaceholder":49},[37,223,224],{"class":39,"line":75},[37,225,226],{},"\u003CCornerRadius x:Key=\"DefaultCornerRadius\">4\u003C\u002FCornerRadius>\n",[15,228,229,230,233,234,233,237,240],{},"动画行为、控件模板、阴影效果、基础控件样式、特殊画刷和模板、路径样式等等，十分的杂乱，在Avalonia版本里，这些都会被拆分为不同的文件中管理，如",[19,231,232],{},"Geometries.axaml","、",[19,235,236],{},"Fonts.axaml",[19,238,239],{},"Effects.axaml","等 Theme.axaml:8-16 ，使主题系统更加模块化（真的及其恶心）。",[10,242,244],{"id":243},"behaviors","Behaviors",[15,246,247],{},"![[Pasted image 20260402172859.png]]",[15,249,250],{},"这个xaml文件封装了6个流体移动行为，用于实现平滑的动画效果。",[28,252,254],{"className":30,"code":253,"language":32,"meta":33,"style":33},"\u003CResourceDictionary xmlns=\"http:\u002F\u002Fschemas.microsoft.com\u002Fwinfx\u002F2006\u002Fxaml\u002Fpresentation\"\n                    xmlns:x=\"http:\u002F\u002Fschemas.microsoft.com\u002Fwinfx\u002F2006\u002Fxaml\"\n                    xmlns:interactivity=\"clr-namespace:HandyControl.Interactivity\">\n\n    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorXY200\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.2\">\n        \u003Cinteractivity:FluidMoveBehavior.EaseX>\n            \u003CPowerEase\u002F>\n        \u003C\u002Finteractivity:FluidMoveBehavior.EaseX>\n        \u003Cinteractivity:FluidMoveBehavior.EaseY>\n            \u003CPowerEase\u002F>\n        \u003C\u002Finteractivity:FluidMoveBehavior.EaseY>\n    \u003C\u002Finteractivity:FluidMoveBehavior>\n\n    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorX200\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.2\">\n        \u003Cinteractivity:FluidMoveBehavior.EaseX>\n            \u003CPowerEase\u002F>\n        \u003C\u002Finteractivity:FluidMoveBehavior.EaseX>\n    \u003C\u002Finteractivity:FluidMoveBehavior>\n\n    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorY200\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.2\">\n        \u003Cinteractivity:FluidMoveBehavior.EaseY>\n            \u003CPowerEase\u002F>\n        \u003C\u002Finteractivity:FluidMoveBehavior.EaseY>\n    \u003C\u002Finteractivity:FluidMoveBehavior>\n\n    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorXY400\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.4\">\n        \u003Cinteractivity:FluidMoveBehavior.EaseX>\n            \u003CPowerEase\u002F>\n        \u003C\u002Finteractivity:FluidMoveBehavior.EaseX>\n        \u003Cinteractivity:FluidMoveBehavior.EaseY>\n            \u003CPowerEase\u002F>\n        \u003C\u002Finteractivity:FluidMoveBehavior.EaseY>\n    \u003C\u002Finteractivity:FluidMoveBehavior>\n\n    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorX400\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.4\">\n        \u003Cinteractivity:FluidMoveBehavior.EaseX>\n            \u003CPowerEase\u002F>\n        \u003C\u002Finteractivity:FluidMoveBehavior.EaseX>\n    \u003C\u002Finteractivity:FluidMoveBehavior>\n\n    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorY400\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.4\">\n        \u003Cinteractivity:FluidMoveBehavior.EaseY>\n            \u003CPowerEase\u002F>\n        \u003C\u002Finteractivity:FluidMoveBehavior.EaseY>\n    \u003C\u002Finteractivity:FluidMoveBehavior>\n\n\u003C\u002FResourceDictionary>\n",[19,255,256,261,266,271,275,280,285,290,295,300,304,309,314,318,323,327,332,337,342,347,353,358,363,368,373,378,384,389,394,399,404,409,414,419,424,430,435,440,445,450,455,461,466,471,476,481,486],{"__ignoreMap":33},[37,257,258],{"class":39,"line":40},[37,259,260],{},"\u003CResourceDictionary xmlns=\"http:\u002F\u002Fschemas.microsoft.com\u002Fwinfx\u002F2006\u002Fxaml\u002Fpresentation\"\n",[37,262,263],{"class":39,"line":46},[37,264,265],{},"                    xmlns:x=\"http:\u002F\u002Fschemas.microsoft.com\u002Fwinfx\u002F2006\u002Fxaml\"\n",[37,267,268],{"class":39,"line":53},[37,269,270],{},"                    xmlns:interactivity=\"clr-namespace:HandyControl.Interactivity\">\n",[37,272,273],{"class":39,"line":59},[37,274,50],{"emptyLinePlaceholder":49},[37,276,277],{"class":39,"line":64},[37,278,279],{},"    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorXY200\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.2\">\n",[37,281,282],{"class":39,"line":70},[37,283,284],{},"        \u003Cinteractivity:FluidMoveBehavior.EaseX>\n",[37,286,287],{"class":39,"line":75},[37,288,289],{},"            \u003CPowerEase\u002F>\n",[37,291,292],{"class":39,"line":81},[37,293,294],{},"        \u003C\u002Finteractivity:FluidMoveBehavior.EaseX>\n",[37,296,297],{"class":39,"line":86},[37,298,299],{},"        \u003Cinteractivity:FluidMoveBehavior.EaseY>\n",[37,301,302],{"class":39,"line":92},[37,303,289],{},[37,305,306],{"class":39,"line":97},[37,307,308],{},"        \u003C\u002Finteractivity:FluidMoveBehavior.EaseY>\n",[37,310,311],{"class":39,"line":103},[37,312,313],{},"    \u003C\u002Finteractivity:FluidMoveBehavior>\n",[37,315,316],{"class":39,"line":108},[37,317,50],{"emptyLinePlaceholder":49},[37,319,320],{"class":39,"line":113},[37,321,322],{},"    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorX200\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.2\">\n",[37,324,325],{"class":39,"line":118},[37,326,284],{},[37,328,330],{"class":39,"line":329},16,[37,331,289],{},[37,333,335],{"class":39,"line":334},17,[37,336,294],{},[37,338,340],{"class":39,"line":339},18,[37,341,313],{},[37,343,345],{"class":39,"line":344},19,[37,346,50],{"emptyLinePlaceholder":49},[37,348,350],{"class":39,"line":349},20,[37,351,352],{},"    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorY200\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.2\">\n",[37,354,356],{"class":39,"line":355},21,[37,357,299],{},[37,359,361],{"class":39,"line":360},22,[37,362,289],{},[37,364,366],{"class":39,"line":365},23,[37,367,308],{},[37,369,371],{"class":39,"line":370},24,[37,372,313],{},[37,374,376],{"class":39,"line":375},25,[37,377,50],{"emptyLinePlaceholder":49},[37,379,381],{"class":39,"line":380},26,[37,382,383],{},"    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorXY400\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.4\">\n",[37,385,387],{"class":39,"line":386},27,[37,388,284],{},[37,390,392],{"class":39,"line":391},28,[37,393,289],{},[37,395,397],{"class":39,"line":396},29,[37,398,294],{},[37,400,402],{"class":39,"line":401},30,[37,403,299],{},[37,405,407],{"class":39,"line":406},31,[37,408,289],{},[37,410,412],{"class":39,"line":411},32,[37,413,308],{},[37,415,417],{"class":39,"line":416},33,[37,418,313],{},[37,420,422],{"class":39,"line":421},34,[37,423,50],{"emptyLinePlaceholder":49},[37,425,427],{"class":39,"line":426},35,[37,428,429],{},"    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorX400\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.4\">\n",[37,431,433],{"class":39,"line":432},36,[37,434,284],{},[37,436,438],{"class":39,"line":437},37,[37,439,289],{},[37,441,443],{"class":39,"line":442},38,[37,444,294],{},[37,446,448],{"class":39,"line":447},39,[37,449,313],{},[37,451,453],{"class":39,"line":452},40,[37,454,50],{"emptyLinePlaceholder":49},[37,456,458],{"class":39,"line":457},41,[37,459,460],{},"    \u003Cinteractivity:FluidMoveBehavior x:Key=\"BehaviorY400\" x:Shared=\"False\" AppliesTo=\"Children\" Duration=\"0:0:.4\">\n",[37,462,464],{"class":39,"line":463},42,[37,465,299],{},[37,467,469],{"class":39,"line":468},43,[37,470,289],{},[37,472,474],{"class":39,"line":473},44,[37,475,308],{},[37,477,479],{"class":39,"line":478},45,[37,480,313],{},[37,482,484],{"class":39,"line":483},46,[37,485,50],{"emptyLinePlaceholder":49},[37,487,489],{"class":39,"line":488},47,[37,490,78],{},[15,492,493,494,497,498,501],{},"有双轴移动效果（X、Y两个一起） 持续200ms 400ms的，也有各个单轴的效果，这些行为都是配置了共同属性x:Shared=“False”可以确保每次使用的时候都会创建新的实例。\n",[19,495,496],{},"AppliesTo=\"Children\""," - 仅应用于子元素， ",[19,499,500],{},"PowerEase"," - 使用PowerEase缓动函数。",[15,503,504,505,509],{},"重点不是动画，而是搞懂为什么要设定共同属性为什么这么设置，一个是通过预定义行为的资源，避免在每个控件中重复配置相同的动画参数，所有",[506,507,508],"strong",{},"行为共享","统一的配置模式，修改时只需更新一处。",[15,511,512],{},"然后是性能方面，每一次使用的是创建实例，可以避免行为实例在多个控件之间共享时可能产生的状态冲突 Theme.xaml:106-113 。",[15,514,515,516,519],{},"PowerEase是一个WPF\u002F.NET Framework的一个缓动函数类，属于",[19,517,518],{},"System.Windows.Media.Animation","命名空间，它继承自EasingFunctionBase，用于创建具有加速和减速效果的动画。",[15,521,522],{},"我们接下来看看行为依赖的interactivity。",[10,524,526],{"id":525},"interactivity","Interactivity",[15,528,529],{},"![[Pasted image 20260402205532.png]]",[15,531,532,533,536],{},"它对应的是",[19,534,535],{},"HandyControl.Interactivity","命名空间，包含以下核心组件：",[15,538,539,540,543,544],{},"Interaction附加属性容器，用于提供",[19,541,542],{},"Interaction.Behaviors","附加属性，",[506,545,546],{},"用于将行为附加到UI元素上",[15,548,549],{},"ControlCommands命令定义，包含控件相关的命令定义，如TabControl中使用的关闭命令等。",[15,551,552],{},"我们先看看Command文件夹：具体是什么？\nControlCommand.cs是命令的总入口，统一定义了很多的RoutedCommand，以及几个自定义的ICommand实例，然后其他的：",[126,554,555,561,567,573,579,585],{},[129,556,557,560],{},[19,558,559],{},"CloseWindowCommand.cs","：关闭当前元素所在窗口",[129,562,563,566],{},[19,564,565],{},"OpenLinkCommand.cs","：打开链接",[129,568,569,572],{},[19,570,571],{},"ShutdownAppCommand.cs","：关闭应用",[129,574,575,578],{},[19,576,577],{},"PushMainWindow2TopCommand.cs","：把主窗口显示并置顶到前台",[129,580,581,584],{},[19,582,583],{},"StartScreenshotCommand.cs","：启动截图",[129,586,587,590,591,594],{},[19,588,589],{},"ScreenshotCommand.cs","：内容与 ",[19,592,593],{},"StartScreenshotCommand"," 基本重复（看起来像历史遗留\u002F重复文件）",[15,596,597],{},"在架构中的作用就是动作语义从控件里抽离出来，避免每个控件自己写一套点击逻辑，让XAML里面可以直接写命令来绑定，比如说Command=\"interactivity:ControlCommands.Prev\"",[15,599,600,601,603],{},"结合 ",[19,602,526],{},"（行为、触发器）时，能做“声明式交互”。你可以把它理解为：控件行为协议层。",[15,605,606],{},"写到这里，是不是显得十分的分散，接下来用一整条回路来解释它的作用。",[608,609,611],"h3",{"id":610},"命令-到组件里","命令 -> 到组件里",[15,613,614,617,618,621,622,625],{},[19,615,616],{},"Theme.xaml"," 的 ",[19,619,620],{},"Pagination"," 模板，把按钮命令写成 ",[19,623,624],{},"ControlCommands.Prev\u002FNext\u002FJump","：",[28,627,629],{"className":30,"code":628,"language":32,"meta":33,"style":33},"\u003CControlTemplate TargetType=\"hc:Pagination\">\n  \u003CStackPanel Orientation=\"Horizontal\" VerticalAlignment=\"Top\">\n    \u003CButton x:Name=\"PART_ButtonLeft\" Command=\"interactivity:ControlCommands.Prev\" \u002F>\n    ...\n    \u003CButton x:Name=\"PART_ButtonRight\" Command=\"interactivity:ControlCommands.Next\" \u002F>\n    ...\n    \u003CButton ... Command=\"interactivity:ControlCommands.Jump\" \u002F>\n  \u003C\u002FStackPanel>\n\u003C\u002FControlTemplate>\n",[19,630,631,636,641,646,651,656,660,665,670],{"__ignoreMap":33},[37,632,633],{"class":39,"line":40},[37,634,635],{},"\u003CControlTemplate TargetType=\"hc:Pagination\">\n",[37,637,638],{"class":39,"line":46},[37,639,640],{},"  \u003CStackPanel Orientation=\"Horizontal\" VerticalAlignment=\"Top\">\n",[37,642,643],{"class":39,"line":53},[37,644,645],{},"    \u003CButton x:Name=\"PART_ButtonLeft\" Command=\"interactivity:ControlCommands.Prev\" \u002F>\n",[37,647,648],{"class":39,"line":59},[37,649,650],{},"    ...\n",[37,652,653],{"class":39,"line":64},[37,654,655],{},"    \u003CButton x:Name=\"PART_ButtonRight\" Command=\"interactivity:ControlCommands.Next\" \u002F>\n",[37,657,658],{"class":39,"line":70},[37,659,650],{},[37,661,662],{"class":39,"line":75},[37,663,664],{},"    \u003CButton ... Command=\"interactivity:ControlCommands.Jump\" \u002F>\n",[37,666,667],{"class":39,"line":81},[37,668,669],{},"  \u003C\u002FStackPanel>\n",[37,671,672],{"class":39,"line":86},[37,673,674],{},"\u003C\u002FControlTemplate>\n",[15,676,677,680,681,625],{},[19,678,679],{},"ControlCommands"," 里把这些命令定义成静态 ",[19,682,683],{},"RoutedCommand",[28,685,689],{"className":686,"code":687,"language":688,"meta":33,"style":33},"language-cs shiki shiki-themes github-light github-dark","public static RoutedCommand Prev { get; } = new(nameof(Prev), typeof(ControlCommands));\npublic static RoutedCommand Next { get; } = new(nameof(Next), typeof(ControlCommands));\npublic static RoutedCommand Jump { get; } = new(nameof(Jump), typeof(ControlCommands));\n","cs",[19,690,691,696,701],{"__ignoreMap":33},[37,692,693],{"class":39,"line":40},[37,694,695],{},"public static RoutedCommand Prev { get; } = new(nameof(Prev), typeof(ControlCommands));\n",[37,697,698],{"class":39,"line":46},[37,699,700],{},"public static RoutedCommand Next { get; } = new(nameof(Next), typeof(ControlCommands));\n",[37,702,703],{"class":39,"line":53},[37,704,705],{},"public static RoutedCommand Jump { get; } = new(nameof(Jump), typeof(ControlCommands));\n",[15,707,708,709,712,713,715],{},"控件构造时注册 ",[19,710,711],{},"CommandBinding","，",[19,714,620],{}," 在构造函数里“接住”这些命令：",[28,717,719],{"className":686,"code":718,"language":688,"meta":33,"style":33},"public Pagination()\n{\n    CommandBindings.Add(new CommandBinding(ControlCommands.Prev, ButtonPrev_OnClick));\n    CommandBindings.Add(new CommandBinding(ControlCommands.Next, ButtonNext_OnClick));\n    CommandBindings.Add(new CommandBinding(ControlCommands.Selected, ToggleButton_OnChecked));\n    CommandBindings.Add(new CommandBinding(ControlCommands.Jump, (s, e) => PageIndex = (int)_jumpNumericUpDown.Value));\n}\n",[19,720,721,726,731,736,741,746,751],{"__ignoreMap":33},[37,722,723],{"class":39,"line":40},[37,724,725],{},"public Pagination()\n",[37,727,728],{"class":39,"line":46},[37,729,730],{},"{\n",[37,732,733],{"class":39,"line":53},[37,734,735],{},"    CommandBindings.Add(new CommandBinding(ControlCommands.Prev, ButtonPrev_OnClick));\n",[37,737,738],{"class":39,"line":59},[37,739,740],{},"    CommandBindings.Add(new CommandBinding(ControlCommands.Next, ButtonNext_OnClick));\n",[37,742,743],{"class":39,"line":64},[37,744,745],{},"    CommandBindings.Add(new CommandBinding(ControlCommands.Selected, ToggleButton_OnChecked));\n",[37,747,748],{"class":39,"line":70},[37,749,750],{},"    CommandBindings.Add(new CommandBinding(ControlCommands.Jump, (s, e) => PageIndex = (int)_jumpNumericUpDown.Value));\n",[37,752,753],{"class":39,"line":75},[37,754,755],{},"}\n",[15,757,758,759,762],{},"最终执行业务逻辑层面上，比如 ",[19,760,761],{},"Prev\u002FNext"," 最后就是改页码：",[28,764,766],{"className":686,"code":765,"language":688,"meta":33,"style":33},"private void ButtonPrev_OnClick(object sender, RoutedEventArgs e) => PageIndex--;\nprivate void ButtonNext_OnClick(object sender, RoutedEventArgs e) => PageIndex++;\n",[19,767,768,773],{"__ignoreMap":33},[37,769,770],{"class":39,"line":40},[37,771,772],{},"private void ButtonPrev_OnClick(object sender, RoutedEventArgs e) => PageIndex--;\n",[37,774,775],{"class":39,"line":46},[37,776,777],{},"private void ButtonNext_OnClick(object sender, RoutedEventArgs e) => PageIndex++;\n",[608,779,781,782,784],{"id":780},"事件-命令interactivity桥接","事件 -> 命令（",[19,783,526],{}," 桥接）",[15,786,787,789,790,793,794,797],{},[19,788,620],{}," 中间那组页码 ",[19,791,792],{},"RadioButton"," 的选中，不是直接 ",[19,795,796],{},"Command=","，而是通过触发器桥接：",[28,799,801],{"className":686,"code":800,"language":688,"meta":33,"style":33},"\u003Cinteractivity:Interaction.Triggers>\n  \u003Cinteractivity:RoutedEventTrigger RoutedEvent=\"RadioButton.Checked\">\n    \u003Cinteractivity:EventToCommand Command=\"interactivity:ControlCommands.Selected\" PassEventArgsToCommand=\"True\" \u002F>\n  \u003C\u002Finteractivity:RoutedEventTrigger>\n\u003C\u002Finteractivity:Interaction.Triggers>\n",[19,802,803,808,813,818,823],{"__ignoreMap":33},[37,804,805],{"class":39,"line":40},[37,806,807],{},"\u003Cinteractivity:Interaction.Triggers>\n",[37,809,810],{"class":39,"line":46},[37,811,812],{},"  \u003Cinteractivity:RoutedEventTrigger RoutedEvent=\"RadioButton.Checked\">\n",[37,814,815],{"class":39,"line":53},[37,816,817],{},"    \u003Cinteractivity:EventToCommand Command=\"interactivity:ControlCommands.Selected\" PassEventArgsToCommand=\"True\" \u002F>\n",[37,819,820],{"class":39,"line":59},[37,821,822],{},"  \u003C\u002Finteractivity:RoutedEventTrigger>\n",[37,824,825],{"class":39,"line":64},[37,826,827],{},"\u003C\u002Finteractivity:Interaction.Triggers>\n",[15,829,830],{},"它的机制就是RoutedEventTrigger监听到路由事件之后，会调用EventToCommand.Invoke，当EventToCommand取到Command的时候会执行CanExecute\u002FExecute来实现关键的实现点。",[28,832,834],{"className":686,"code":833,"language":688,"meta":33,"style":33},"protected override void Invoke(object parameter)\n{\n    ...\n    if (command == null || !command.CanExecute(parameter1))\n        return;\n    command.Execute(parameter1);\n}\n",[19,835,836,841,845,849,854,859,864],{"__ignoreMap":33},[37,837,838],{"class":39,"line":40},[37,839,840],{},"protected override void Invoke(object parameter)\n",[37,842,843],{"class":39,"line":46},[37,844,730],{},[37,846,847],{"class":39,"line":53},[37,848,650],{},[37,850,851],{"class":39,"line":59},[37,852,853],{},"    if (command == null || !command.CanExecute(parameter1))\n",[37,855,856],{"class":39,"line":64},[37,857,858],{},"        return;\n",[37,860,861],{"class":39,"line":70},[37,862,863],{},"    command.Execute(parameter1);\n",[37,865,866],{"class":39,"line":75},[37,867,755],{},[608,869,871],{"id":870},"自定义icommand","自定义Icommand",[15,873,874,875,712,877,879,880,883],{},"除了 ",[19,876,683],{},[19,878,679],{}," 也暴露了直接可执行的 ",[19,881,882],{},"ICommand"," 实例：",[28,885,887],{"className":686,"code":886,"language":688,"meta":33,"style":33},"public static CloseWindowCommand CloseWindow { get; } = new();\n",[19,888,889],{"__ignoreMap":33},[37,890,891],{"class":39,"line":40},[37,892,886],{},[15,894,895],{},"Demo 里直接用：",[28,897,899],{"className":686,"code":898,"language":688,"meta":33,"style":33},"\u003CButton Command=\"hc:ControlCommands.CloseWindow\" CommandParameter=\"{Binding RelativeSource={RelativeSource Self}}\" ...\u002F>\n",[19,900,901],{"__ignoreMap":33},[37,902,903],{"class":39,"line":40},[37,904,898],{},[15,906,907,908,911],{},"命令实现就是：拿 ",[19,909,910],{},"CommandParameter"," 对应元素，找到所在窗口并关闭：",[28,913,915],{"className":686,"code":914,"language":688,"meta":33,"style":33},"public void Execute(object parameter)\n{\n    if (parameter is DependencyObject dependencyObject)\n    {\n        if (Window.GetWindow(dependencyObject) is { } window)\n        {\n            window.Close();\n        }\n    }\n}\n",[19,916,917,922,926,931,936,941,946,951,956,961],{"__ignoreMap":33},[37,918,919],{"class":39,"line":40},[37,920,921],{},"public void Execute(object parameter)\n",[37,923,924],{"class":39,"line":46},[37,925,730],{},[37,927,928],{"class":39,"line":53},[37,929,930],{},"    if (parameter is DependencyObject dependencyObject)\n",[37,932,933],{"class":39,"line":59},[37,934,935],{},"    {\n",[37,937,938],{"class":39,"line":64},[37,939,940],{},"        if (Window.GetWindow(dependencyObject) is { } window)\n",[37,942,943],{"class":39,"line":70},[37,944,945],{},"        {\n",[37,947,948],{"class":39,"line":75},[37,949,950],{},"            window.Close();\n",[37,952,953],{"class":39,"line":81},[37,954,955],{},"        }\n",[37,957,958],{"class":39,"line":86},[37,959,960],{},"    }\n",[37,962,963],{"class":39,"line":92},[37,964,755],{},[15,966,967],{},"总结来说，ControlCommand会统一动作名册，Theme.xaml会把命令挂到可视元素，控件类CommandBindings会把命令映射到控件内部的逻辑。Interactivity会把事件桥接成命令，减少code-behind。",[15,969,970],{},"除开command文件，就是事件转命令的实现EventToCommand：",[608,972,974],{"id":973},"eventtocommand","EventToCommand",[15,976,977,978,980],{},"为什么需要这个文件？ 因为很多WPF很多事件不能直接优雅的走命令，但是组件库又想要模板层没有code-behind，实现交互统一命令化，",[19,979,974],{}," 就是为这个缺口做的桥接器。",[15,982,983,984,987,988,991,992,995],{},"就比如说你有一个事件MouseMove，但是你希望执行ICommand，你想要写纯XAML来交互，不用写页面代码后置，还可以把控件启用状态跟CanExecue联动。",[19,985,986],{},"Button"," 这种有 ",[19,989,990],{},"Command"," 属性的控件可以直接绑命令，但很多交互是“事件型”的（尤其在 ",[19,993,994],{},"Style\u002FControlTemplate","、触发器场景），不总能直接命令绑定",[15,997,998],{},"就比如说这里：",[28,1000,1002],{"className":30,"code":1001,"language":32,"meta":33,"style":33},"\u003Cinteractivity:Interaction.Triggers>  \n    \u003Cinteractivity:RoutedEventTrigger RoutedEvent=\"RadioButton.Checked\">  \n       \u003Cinteractivity:EventToCommand Command=\"interactivity:ControlCommands.Selected\" PassEventArgsToCommand=\"True\" \u002F>  \n    \u003C\u002Finteractivity:RoutedEventTrigger>  \n\u003C\u002Finteractivity:Interaction.Triggers>\n",[19,1003,1004,1009,1014,1019,1024],{"__ignoreMap":33},[37,1005,1006],{"class":39,"line":40},[37,1007,1008],{},"\u003Cinteractivity:Interaction.Triggers>  \n",[37,1010,1011],{"class":39,"line":46},[37,1012,1013],{},"    \u003Cinteractivity:RoutedEventTrigger RoutedEvent=\"RadioButton.Checked\">  \n",[37,1015,1016],{"class":39,"line":53},[37,1017,1018],{},"       \u003Cinteractivity:EventToCommand Command=\"interactivity:ControlCommands.Selected\" PassEventArgsToCommand=\"True\" \u002F>  \n",[37,1020,1021],{"class":39,"line":59},[37,1022,1023],{},"    \u003C\u002Finteractivity:RoutedEventTrigger>  \n",[37,1025,1026],{"class":39,"line":64},[37,1027,827],{},[15,1029,1030,1031,1034,1035,1038,1039,1041],{},"这里会在容器上挂载触发器，来监听冒泡上来的RadioButton.Checked事件，然后执行EventToCommand，EventToCommand会调用ControlCommands.Selected.Execute(...)， ",[19,1032,1033],{},"PassEventArgsToCommand=\"True\"","：把这次事件参数（",[19,1036,1037],{},"RoutedEventArgs","）作为命令参数传入（如果没显式 ",[19,1040,910],{},"）。",[15,1043,1044],{},"![[Pasted image 20260402213939.png]]",[15,1046,1047,1048,1051,1052,1054],{},"有了它的帮助，我们可以把事件触发转换为命令执行，让你在 XAML 里不用写 ",[19,1049,1050],{},"Click"," 代码后置，而是通过触发器把事件映射到 ",[19,1053,882],{},"。这个文件做了四件事：",[126,1056,1057,1064,1073,1080],{},[129,1058,1059,1060,233,1062],{},"接收命令与参数：",[19,1061,990],{},[19,1063,910],{},[129,1065,1066,1067,233,1070],{},"支持把事件参数传给命令：",[19,1068,1069],{},"PassEventArgsToCommand",[19,1071,1072],{},"EventArgsConverter",[129,1074,1075,1076,1079],{},"执行前做可执行判断：",[19,1077,1078],{},"CanExecute"," 不通过就不执行",[129,1081,1082,1083,1086,1087,1089,1090],{},"可选联动控件启用状态：",[19,1084,1085],{},"MustToggleIsEnabled"," 时自动根据 ",[19,1088,1078],{}," 设置控件 ",[19,1091,1092],{},"IsEnabled",[15,1094,1095],{},"这里TriggerAction触发器接受的类型是DependencyObject，他可以提供数据绑定、样式\u002F模板的Setter赋值。以及动画和属性值继承，还能实现默认值、回调、校验、coerce等机制(依赖属性被设置的时候，WPF在真正生效前，给你一次强制修正值的机会)，WPF中绝大部分UI对象都在这条继承链上。",[15,1097,1098],{},"你可以打开DependencyObject来看看究竟有哪些：\n![[Pasted image 20260402214930.png]]",[15,1100,1101,1102,1105,1106,1109,1110,1113],{},"这里的## ",[19,1103,1104],{},"[NameScopeProperty(\"NameScope\", typeof(NameScope))]","意思就是在xaml设计器中可以得到NameScope属性，来关系x:Name命名作用域， ",[19,1107,1108],{},"NameScope"," 的作用是：在某个作用域内，名字唯一，并支持 ",[19,1111,1112],{},"FindName","、Storyboard 目标解析等。",[15,1115,1116,1117,1119,1120,1123,1124,1127,1128],{},"回到刚才的话题，它注册了几个依赖属性，- 给 ",[19,1118,974],{}," 提供一个",[506,1121,1122],{},"可绑定的参数入口","（XAML\u002FBinding 可赋值）， 这个参数会在触发时传给命令的 ",[19,1125,1126],{},"Execute(parameter)"," \u002F ",[19,1129,1130],{},"CanExecute(parameter)",[608,1132,1134],{"id":1133},"mousedragelementbehaviorex","MouseDragElementBehaviorEx",[15,1136,1137],{},"这个文件是反编译微软的System.Windows.Interactivity程序集得到的，并对其做了些扩展。他们做了LockX和LockY两个轴向锁属性，在位移应用处加入了轴向判断，代码里也写了“在该处对微软的类进行了修改”）：",[126,1139,1140,1160],{},[129,1141,1142,1145,1146,1149,1150,1153,1154,1149,1157],{},[19,1143,1144],{},"MatrixTransform"," 分支里，只有 ",[19,1147,1148],{},"!LockX"," 才改 ",[19,1151,1152],{},"OffsetX","，只有 ",[19,1155,1156],{},"!LockY",[19,1158,1159],{},"OffsetY",[129,1161,1162,1165],{},[19,1163,1164],{},"TranslateTransform"," 分支同理，只在未锁定轴上累加位移",[15,1167,1168,1169,1172],{},"也就是把原来“自由拖拽（X\u002FY都动）”扩展成“可限制只横向拖或只纵向拖”。这样就得到了一个可以附加到",[19,1170,1171],{},"FrameworkElement"," 的拖拽行为（Behavior），核心能力：",[126,1174,1175,1178,1185,1188,1195,1208],{},[129,1176,1177],{},"鼠标按下开始拖拽（捕获鼠标）",[129,1179,1180,1181,1184],{},"鼠标移动实时更新元素位置（通过 ",[19,1182,1183],{},"RenderTransform"," 平移）",[129,1186,1187],{},"鼠标抬起\u002F失去捕获结束拖拽",[129,1189,1190,1191,1194],{},"可选限制在父容器边界内（",[19,1192,1193],{},"ConstrainToParentBounds","）",[129,1196,1197,1198,1201,1202,233,1205,1194],{},"通过",[506,1199,1200],{},"依赖属性","暴露当前位置（",[19,1203,1204],{},"X",[19,1206,1207],{},"Y",[129,1209,1210,1211,1127,1214,1127,1217],{},"暴露拖拽生命周期事件：",[19,1212,1213],{},"DragBegun",[19,1215,1216],{},"Dragging",[19,1218,1219],{},"DragFinished",[15,1221,1222,1223,1226,1227,1230],{},"这是一个“可配置的 UI 拖拽引擎”：",[1224,1225],"br",{},"\n在微软原版 ",[19,1228,1229],{},"MouseDragElementBehavior"," 基础上，HandyControl 增强了锁轴拖动（LockX\u002FLockY），更适合做窗口条、滑块、面板等只允许单轴移动的交互。",[1232,1233,1234],"h4",{"id":1234},"behavior",[15,1236,1237],{},"这里使用或者说继承的behavior其实是作者们改良过的：![[Pasted image 20260402224005.png]]",[15,1239,1240,1241,233,1244,233,1246,1248],{},"这里的AssociatedObject指的是Behavior当前附加到的哪个对象的实例，当你在 XAML 里给某个元素加 Behavior 时（比如给 ",[19,1242,1243],{},"Grid",[19,1245,986],{},[19,1247,1171],{},"）：",[126,1250,1251,1257,1262],{},[129,1252,1253,1256],{},[19,1254,1255],{},"Attach(dependencyObject)"," 被调用",[129,1258,1259],{},[19,1260,1261],{},"_associatedObject = dependencyObject",[129,1263,1264,1265,1268,1269,1272],{},"之后 ",[19,1266,1267],{},"OnAttached()"," 里你就可以通过 ",[19,1270,1271],{},"AssociatedObject"," 操作该元素（订阅事件、改属性等）",[15,1274,1275],{},"我们熟知的DragBehavior就是这样生效的！！",[15,1277,1278,1279,1282],{},"那么这里为什么不直接写Behavior\u003C>里面Dep..Object来约束呢，为什么非要where来泛型约束。如果真的像前面这样来写的话，等于把类型信息丢了，子类里你还是要反复强转。",[19,1280,1281],{},"Behavior\u003CT>"," 的意义是把“宿主类型约束”前置到编译期。",[15,1284,1285,1286,1289,1290,1194],{},"这么说你就懂了， ",[19,1287,1288],{},"DependencyObject"," 太宽泛：Window、Button、Transform、Brush 都是它体系里的类型 你的行为通常只适用于某一类宿主（比如 ",[19,1291,1171],{},[126,1293,1294],{},[129,1295,1296,1297,1300,1301],{},"用泛型 ",[19,1298,1299],{},"T"," 可以：\n",[126,1302,1303,1308,1311],{},[129,1304,1305,1306],{},"编译期拿到强类型 ",[19,1307,1271],{},[129,1309,1310],{},"Attach 时自动做类型约束检查",[129,1312,1313],{},"减少运行时 cast\u002F空判断和错误",[608,1315,1317],{"id":1316},"routedeventtrigger","RoutedEventTrigger",[15,1319,1320,1321,712,1324,1327,1328,1330],{},"这个文件的职责很清晰，监听一个指定的 ",[19,1322,1323],{},"RoutedEvent",[506,1325,1326],{},"一旦触发就把事件转发给触发器","动作链（比如 ",[19,1329,974],{},"）。![[Pasted image 20260402225354.png]]",[15,1332,1333],{},"和我们刚才看到的",[28,1335,1337],{"className":30,"code":1336,"language":32,"meta":33,"style":33},"\u003Cinteractivity:Interaction.Triggers>\n    \u003Cinteractivity:RoutedEventTrigger RoutedEvent=\"RadioButton.Checked\">\n        \u003Cinteractivity:EventToCommand\n            Command=\"interactivity:ControlCommands.Selected\"\n            PassEventArgsToCommand=\"True\" \u002F>\n    \u003C\u002Finteractivity:RoutedEventTrigger>\n\u003C\u002Finteractivity:Interaction.Triggers>\n",[19,1338,1339,1343,1348,1353,1358,1363,1368],{"__ignoreMap":33},[37,1340,1341],{"class":39,"line":40},[37,1342,807],{},[37,1344,1345],{"class":39,"line":46},[37,1346,1347],{},"    \u003Cinteractivity:RoutedEventTrigger RoutedEvent=\"RadioButton.Checked\">\n",[37,1349,1350],{"class":39,"line":53},[37,1351,1352],{},"        \u003Cinteractivity:EventToCommand\n",[37,1354,1355],{"class":39,"line":59},[37,1356,1357],{},"            Command=\"interactivity:ControlCommands.Selected\"\n",[37,1359,1360],{"class":39,"line":64},[37,1361,1362],{},"            PassEventArgsToCommand=\"True\" \u002F>\n",[37,1364,1365],{"class":39,"line":70},[37,1366,1367],{},"    \u003C\u002Finteractivity:RoutedEventTrigger>\n",[37,1369,1370],{"class":39,"line":75},[37,1371,827],{},[15,1373,1374],{},"这段代码完全相关",[10,1376,1378],{"id":1377},"brushes文件","Brushes文件",[15,1380,1381],{},"这个是颜色到画刷的中间层，我们之前见到的Color颜色不能直接使用，我们需要封装为可以给控件使用的Brush资源：",[15,1383,1384],{},"![[Pasted image 20260402231018.png]]",[10,1386,1388],{"id":1387},"conveters-转换器","Conveters 转换器",[15,1390,1391],{},"![[Pasted image 20260402231347.png]]",[15,1393,1394],{},"它是“全局转换器注册表”",[15,1396,1397,1398,1127,1401,1404,1405,1408],{},"把 HandyControl 里常用的 ",[19,1399,1400],{},"IValueConverter",[19,1402,1403],{},"IMultiValueConverter"," 统一注册成可复用资源，供所有样式模板直接 ",[19,1406,1407],{},"StaticResource"," 引用。",[126,1410,1411,1420,1429,1441,1450],{},[129,1412,1413,1414,233,1417],{},"布尔和可见性：",[19,1415,1416],{},"Boolean2VisibilityConverter",[19,1418,1419],{},"Boolean2VisibilityReConverter",[129,1421,1422,1423,233,1426],{},"反转\u002F组合逻辑：",[19,1424,1425],{},"Boolean2BooleanReConverter",[19,1427,1428],{},"BooleanArr2BooleanConverter",[129,1430,1431,1432,233,1435,233,1438],{},"布局\u002F图形：",[19,1433,1434],{},"CornerRadiusSplitConverter",[19,1436,1437],{},"ThicknessSplitConverter",[19,1439,1440],{},"BorderClipConverter",[129,1442,1443,1444,233,1447],{},"文本\u002F数值：",[19,1445,1446],{},"Int2StringConverter",[19,1448,1449],{},"Number2PercentageConverter",[129,1451,1452,1453,233,1456],{},"控件特定：",[19,1454,1455],{},"TreeViewItemMarginConverter",[19,1457,1458],{},"DataGridSelectAllButtonVisibilityConverter",[15,1460,1461],{},"为什么单独放一个文件",[126,1463,1464,1467,1470],{},[129,1465,1466],{},"主题模板大量依赖 converter，集中定义可避免重复创建和重复声明",[129,1468,1469],{},"统一 key，样式里直接用，降低模板复杂度",[129,1471,1472],{},"作为主题基础资源的一部分，随主题一起合并加载",[10,1474,1476],{"id":1475},"effect文件","Effect文件",[15,1478,1479],{},"这个用于主题里的阴影效果资源表",[28,1481,1483],{"className":30,"code":1482,"language":32,"meta":33,"style":33},"\u003CResourceDictionary xmlns=\"http:\u002F\u002Fschemas.microsoft.com\u002Fwinfx\u002F2006\u002Fxaml\u002Fpresentation\"\n                    xmlns:x=\"http:\u002F\u002Fschemas.microsoft.com\u002Fwinfx\u002F2006\u002Fxaml\"\n                    xmlns:o=\"http:\u002F\u002Fschemas.microsoft.com\u002Fwinfx\u002F2006\u002Fxaml\u002Fpresentation\u002Foptions\">\n\n    \u003CColor x:Key=\"EffectShadowColor\">#88000000\u003C\u002FColor>\n\n    \u003CDropShadowEffect x:Key=\"EffectShadow1\" BlurRadius=\"5\" ShadowDepth=\"1\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n    \u003CDropShadowEffect x:Key=\"EffectShadow2\" BlurRadius=\"8\" ShadowDepth=\"1.5\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n    \u003CDropShadowEffect x:Key=\"EffectShadow3\" BlurRadius=\"14\" ShadowDepth=\"4.5\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n    \u003CDropShadowEffect x:Key=\"EffectShadow4\" BlurRadius=\"25\" ShadowDepth=\"8\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n    \u003CDropShadowEffect x:Key=\"EffectShadow5\" BlurRadius=\"35\" ShadowDepth=\"13\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n\n\u003C\u002FResourceDictionary>\n\n",[19,1484,1485,1489,1493,1498,1502,1507,1511,1516,1521,1526,1531,1536,1540],{"__ignoreMap":33},[37,1486,1487],{"class":39,"line":40},[37,1488,260],{},[37,1490,1491],{"class":39,"line":46},[37,1492,265],{},[37,1494,1495],{"class":39,"line":53},[37,1496,1497],{},"                    xmlns:o=\"http:\u002F\u002Fschemas.microsoft.com\u002Fwinfx\u002F2006\u002Fxaml\u002Fpresentation\u002Foptions\">\n",[37,1499,1500],{"class":39,"line":59},[37,1501,50],{"emptyLinePlaceholder":49},[37,1503,1504],{"class":39,"line":64},[37,1505,1506],{},"    \u003CColor x:Key=\"EffectShadowColor\">#88000000\u003C\u002FColor>\n",[37,1508,1509],{"class":39,"line":70},[37,1510,50],{"emptyLinePlaceholder":49},[37,1512,1513],{"class":39,"line":75},[37,1514,1515],{},"    \u003CDropShadowEffect x:Key=\"EffectShadow1\" BlurRadius=\"5\" ShadowDepth=\"1\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n",[37,1517,1518],{"class":39,"line":81},[37,1519,1520],{},"    \u003CDropShadowEffect x:Key=\"EffectShadow2\" BlurRadius=\"8\" ShadowDepth=\"1.5\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n",[37,1522,1523],{"class":39,"line":86},[37,1524,1525],{},"    \u003CDropShadowEffect x:Key=\"EffectShadow3\" BlurRadius=\"14\" ShadowDepth=\"4.5\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n",[37,1527,1528],{"class":39,"line":92},[37,1529,1530],{},"    \u003CDropShadowEffect x:Key=\"EffectShadow4\" BlurRadius=\"25\" ShadowDepth=\"8\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n",[37,1532,1533],{"class":39,"line":97},[37,1534,1535],{},"    \u003CDropShadowEffect x:Key=\"EffectShadow5\" BlurRadius=\"35\" ShadowDepth=\"13\" Direction=\"270\" Color=\"{StaticResource EffectShadowColor}\" Opacity=\".2\" RenderingBias=\"Performance\" o:Freeze=\"True\" \u002F>\n",[37,1537,1538],{"class":39,"line":103},[37,1539,50],{"emptyLinePlaceholder":49},[37,1541,1542],{"class":39,"line":108},[37,1543,78],{},[15,1545,1546,1547,1550,1551,625,1554,1557,1558,1561],{},"这里共享了一个半透明黑色：",[19,1548,1549],{},"EffectShadowColor","。 五档 ",[19,1552,1553],{},"DropShadowEffect",[19,1555,1556],{},"EffectShadow1","～",[19,1559,1560],{},"EffectShadow5","，模糊半径和阴影深度递增，用于不同强度的卡片\u002F浮层阴影",[126,1563,1564,1573],{},[129,1565,1566,1567,1570,1571],{},"控件模板里用 ",[19,1568,1569],{},"Effect=\"{StaticResource EffectShadow3}\""," 这类写法，统一视觉、避免每个控件手写一遍 ",[19,1572,1553],{},[129,1574,1575,1578],{},[19,1576,1577],{},"o:Freeze=\"True\"","：冻结为不可变对象，便于性能与共享",[15,1580,1581,1582,233,1585,1588],{},"和 ",[19,1583,1584],{},"Brushes.xaml",[19,1586,1587],{},"Converters.xaml"," 一样，属于基础主题资源，被合并进主主题后全局复用。",[10,1590,1592],{"id":1591},"fonts文件","Fonts文件",[15,1594,1595],{},"这个就和名字一样，定义了各种文字的大小。![[Pasted image 20260403160604.png]]",[15,1597,1598,1599,1601,1602,233,1605,233,1608,1611],{},"在 ",[19,1600,616],{}," 顶部已经能看到类似资源被使用（比如 ",[19,1603,1604],{},"LargeFontSize",[19,1606,1607],{},"HeadFontSize",[19,1609,1610],{},"TextFontSize"," 这种 key），这些就是供控件样式统一引用的。",[10,1613,1615],{"id":1614},"geometry","Geometry",[15,1617,1618,1619,1621],{},"这个文件定义了可复用的矢量几何资源（",[19,1620,1615],{},"）。在主题体系里它通常负责这类内容：",[126,1623,1624,1627,1630],{},[129,1625,1626],{},"各种图标路径（关闭、箭头、搜索、旋转、保存等）",[129,1628,1629],{},"复杂矢量形状（控件内部装饰用）",[129,1631,1632,1633,233,1636,1639],{},"统一 key（如 ",[19,1634,1635],{},"CloseGeometry",[19,1637,1638],{},"LeftGeometry","），供样式和模板复用",[15,1641,1642,1643,1646,1647,1650],{},"单独放在这个文件里的原因是为了避免每个模块里重复编写长Path Data，并且图标视觉统一就可以实现低维护成本， 配合 ",[19,1644,1645],{},"Path Data=\"{StaticResource XxxGeometry}\""," ",[506,1648,1649],{},"使用很干净","。",[15,1652,1653,1655],{},[19,1654,616],{}," 里已经能看到它的使用方式，比如按钮模板里常见：",[126,1657,1658,1663],{},[129,1659,1660],{},[19,1661,1662],{},"hc:IconElement.Geometry=\"{StaticResource LeftGeometry}\"",[129,1664,1665],{},[19,1666,1667],{},"...=\"{StaticResource CloseGeometry}\"",[15,1669,1670],{},"![[Pasted image 20260403161431.png]]",[10,1672,1674],{"id":1673},"path文件夹","Path文件夹",[15,1676,1677,1678,1681,1682,1684],{},"它的任务就是把刚才的几何层封装成可以直接使用的Path 样式， ",[19,1679,1680],{},"Geometries.xaml","：只提供 ",[19,1683,1615],{}," 数据（图标“形状原料”）。",[15,1686,1687],{},"![[Pasted image 20260403161523.png]]",[10,1689,1691],{"id":1690},"size文件","Size文件",[15,1693,1694],{},"它的作用是集中定义尺寸相关的主题常量资源，给全局的样式和控件模板统一使用。在 HandyControl 这种主题体系里，它一般会包含类似这些 key：",[126,1696,1697,1700,1703,1706],{},[129,1698,1699],{},"控件高度（默认\u002F小号）",[129,1701,1702],{},"圆角半径（默认\u002F胶囊）",[129,1704,1705],{},"边距、间距、内边距",[129,1707,1708],{},"图标尺寸、线宽等\n![[Pasted image 20260403161633.png]]",[10,1710,1712],{"id":1711},"base文件夹","Base文件夹",[15,1714,1715,1718],{},[19,1716,1717],{},"Themes\u002FStyles\u002FBase"," 里放的是各控件的“基础样式模板层”，可以理解成“样式骨架”。控件默认使用的是ControlTemplate，通用Setter，边框、内边距、状态触发器。以及设置了供上层使用的x:key。 这个也是组件设计的基本功，先定义可重复使用的基础外观和行为，外层样式再去轻量定制。![[Pasted image 20260403165637.png]]",[15,1720,1721,1722,617,1725,1728,1729,1732,1733,1736,1737,1739,1742,1744,1745,1748],{},"就像上面的，我们看到的这个基础的样式，它最终会被作为下拉项样式来使用。具体关系是： ",[19,1723,1724],{},"AutoCompleteTextBoxItemBaseStyle",[19,1726,1727],{},"TargetType"," 是 ",[19,1730,1731],{},"ComboBoxItem"," 。\n在 ",[19,1734,1735],{},"AutoCompleteTextBoxBaseStyle"," 里通过",[1224,1738],{},[19,1740,1741],{},"ItemContainerStyle = {StaticResource AutoCompleteTextBoxItemBaseStyle}",[1224,1743],{},"\n应用给 ",[19,1746,1747],{},"hc:AutoCompleteTextBox"," 的每一项",[15,1750,1751],{},"我们可以直接看一下AutoCompleteTextBox在哪里，![[Pasted image 20260403174939.png]]",[15,1753,1754],{},"这里就是定义了这个组件的地方。",[15,1756,1757],{},"我们主要学习的就是别人是怎么自定义组件的，因此这段代码我们重点来研究，之后我们也会这样来完成。",[28,1759,1764],{"className":1760,"code":1762,"language":1763},[1761],"language-text","[TemplatePart(Name = SearchTextBox, Type = typeof(System.Windows.Controls.TextBox))]\n","text",[19,1765,1762],{"__ignoreMap":33},[15,1767,1768,1769,1772,1773,1776,1777,1780],{},"这个特性用于声明“这个自定义控件的模板里，预期应该有哪个命名部件（",[19,1770,1771],{},"PART_...","）以及它的类型”。\n里应包含了名为SearchTextBox，通常是某个PART_xxx常量值的元素，该元素类型是TextBox。这样的模式便于开发者一个模板提醒（提醒这个模板里应该有一个名为SearchTextBox的部件，类型是TextBox，但是真正的控件实例必须在ControlTemplate里面自己写出来，比如说x:Name=\"PART_SearchTextBox\"，刚才我们看到了）。 便于控件在 ",[19,1774,1775],{},"OnApplyTemplate()"," 里用 ",[19,1778,1779],{},"GetTemplateChild(...)"," 取到部件并绑定逻辑",[126,1782,1783,1786],{},[129,1784,1785],{},"这个特性本身不强制运行时校验",[129,1787,1788,1789,1792],{},"真正是否存在、能不能用，要看控件代码在 ",[19,1790,1791],{},"OnApplyTemplate"," 里怎么处理（判空\u002F抛错等）",[10,1794,1795],{"id":1795},"资源加载",[15,1797,1798,1799,1802,1803,1806,1807,1810],{},"在WPF中，资源字典可能会",[506,1800,1801],{},"重复加载导致的内存膨胀","。如果在大型项目中，不使用",[19,1804,1805],{},"SharedResourceDictionary","，每当你引用一次通用的 XAML 资源（比如 ",[19,1808,1809],{},"Colors.xaml","），系统就会在内存中完整地重新创建一套这些对象的副本。",[15,1812,1813,1814,1817],{},"在标准的 ",[19,1815,1816],{},"ResourceDictionary"," 中，当你这样写：",[28,1819,1821],{"className":30,"code":1820,"language":32,"meta":33,"style":33},"\u003CResourceDictionary.MergedDictionaries>\n    \u003CResourceDictionary Source=\"pack:\u002F\u002Fapplication:,,,\u002FHandyControl;component\u002FThemes\u002FSkinDefault.xaml\"\u002F>\n\u003C\u002FResourceDictionary.MergedDictionaries>\n",[19,1822,1823,1828,1833],{"__ignoreMap":33},[37,1824,1825],{"class":39,"line":40},[37,1826,1827],{},"\u003CResourceDictionary.MergedDictionaries>\n",[37,1829,1830],{"class":39,"line":46},[37,1831,1832],{},"    \u003CResourceDictionary Source=\"pack:\u002F\u002Fapplication:,,,\u002FHandyControl;component\u002FThemes\u002FSkinDefault.xaml\"\u002F>\n",[37,1834,1835],{"class":39,"line":53},[37,1836,1837],{},"\u003C\u002FResourceDictionary.MergedDictionaries>\n",[15,1839,1840],{},"如果你有100个窗口或者是用户控件都会引用这个文件的话，WPF就会默认解析和加载100次，十分耗费CPU，因此我们可以使用一个静态的缓存池接管加载过程。",[15,1842,1843],{},[19,1844,1845],{},"public static Dictionary\u003CUri, ResourceDictionary> SharedDictionaries = new();",[15,1847,1848,1849,1852,1853,1856,1857,1859],{},"这是一个",[506,1850,1851],{},"全局共享的字典","。它以 ",[19,1854,1855],{},"Uri","（资源路径）作为 Key，已经解析好的 ",[19,1858,1816],{}," 对象作为 Value。",[28,1861,1863],{"className":686,"code":1862,"language":688,"meta":33,"style":33},"public class SharedResourceDictionary : ResourceDictionary\n{\n    public static Dictionary\u003CUri, ResourceDictionary> SharedDictionaries = new();\n\n    private Uri _sourceUri;\n\n    public new Uri Source\n    {\n        get => DesignerHelper.IsInDesignMode ? base.Source : _sourceUri;\n        set\n        {\n            if (value == null) return;\n            if (DesignerHelper.IsInDesignMode)\n            {\n                base.Source = value;\n                return;\n            }\n            _sourceUri = value;\n\n            if (!SharedDictionaries.ContainsKey(value))\n            {\n                base.Source = value;\n                SharedDictionaries.Add(value, this);\n            }\n            else\n            {\n                MergedDictionaries.Add(SharedDictionaries[value]);\n            }\n        }\n    }\n}\n\n",[19,1864,1865,1870,1874,1879,1883,1888,1892,1897,1901,1906,1911,1915,1920,1925,1930,1935,1940,1945,1950,1954,1959,1963,1967,1972,1976,1981,1985,1990,1994,1998,2002],{"__ignoreMap":33},[37,1866,1867],{"class":39,"line":40},[37,1868,1869],{},"public class SharedResourceDictionary : ResourceDictionary\n",[37,1871,1872],{"class":39,"line":46},[37,1873,730],{},[37,1875,1876],{"class":39,"line":53},[37,1877,1878],{},"    public static Dictionary\u003CUri, ResourceDictionary> SharedDictionaries = new();\n",[37,1880,1881],{"class":39,"line":59},[37,1882,50],{"emptyLinePlaceholder":49},[37,1884,1885],{"class":39,"line":64},[37,1886,1887],{},"    private Uri _sourceUri;\n",[37,1889,1890],{"class":39,"line":70},[37,1891,50],{"emptyLinePlaceholder":49},[37,1893,1894],{"class":39,"line":75},[37,1895,1896],{},"    public new Uri Source\n",[37,1898,1899],{"class":39,"line":81},[37,1900,935],{},[37,1902,1903],{"class":39,"line":86},[37,1904,1905],{},"        get => DesignerHelper.IsInDesignMode ? base.Source : _sourceUri;\n",[37,1907,1908],{"class":39,"line":92},[37,1909,1910],{},"        set\n",[37,1912,1913],{"class":39,"line":97},[37,1914,945],{},[37,1916,1917],{"class":39,"line":103},[37,1918,1919],{},"            if (value == null) return;\n",[37,1921,1922],{"class":39,"line":108},[37,1923,1924],{},"            if (DesignerHelper.IsInDesignMode)\n",[37,1926,1927],{"class":39,"line":113},[37,1928,1929],{},"            {\n",[37,1931,1932],{"class":39,"line":118},[37,1933,1934],{},"                base.Source = value;\n",[37,1936,1937],{"class":39,"line":329},[37,1938,1939],{},"                return;\n",[37,1941,1942],{"class":39,"line":334},[37,1943,1944],{},"            }\n",[37,1946,1947],{"class":39,"line":339},[37,1948,1949],{},"            _sourceUri = value;\n",[37,1951,1952],{"class":39,"line":344},[37,1953,50],{"emptyLinePlaceholder":49},[37,1955,1956],{"class":39,"line":349},[37,1957,1958],{},"            if (!SharedDictionaries.ContainsKey(value))\n",[37,1960,1961],{"class":39,"line":355},[37,1962,1929],{},[37,1964,1965],{"class":39,"line":360},[37,1966,1934],{},[37,1968,1969],{"class":39,"line":365},[37,1970,1971],{},"                SharedDictionaries.Add(value, this);\n",[37,1973,1974],{"class":39,"line":370},[37,1975,1944],{},[37,1977,1978],{"class":39,"line":375},[37,1979,1980],{},"            else\n",[37,1982,1983],{"class":39,"line":380},[37,1984,1929],{},[37,1986,1987],{"class":39,"line":386},[37,1988,1989],{},"                MergedDictionaries.Add(SharedDictionaries[value]);\n",[37,1991,1992],{"class":39,"line":391},[37,1993,1944],{},[37,1995,1996],{"class":39,"line":396},[37,1997,955],{},[37,1999,2000],{"class":39,"line":401},[37,2001,960],{},[37,2003,2004],{"class":39,"line":406},[37,2005,755],{},[15,2007,2008,2009,2012,2013,2016,2017,2020,2021,2024,2025,2028],{},"他通过new关键字隐藏了基类的Source属性，可以重新定义赋值逻辑，当设置 ",[19,2010,2011],{},"Source"," 时，先去 ",[19,2014,2015],{},"SharedDictionaries"," 看看这个路径的资源是否已经加载过了。如果没加载过，调用 ",[19,2018,2019],{},"base.Source = value"," 进行解析，并把结果存入静态字典。如果已经加载过，",[506,2022,2023],{},"不再重新解析","，而是直接把缓存中的实例添加到当前的 ",[19,2026,2027],{},"MergedDictionaries"," 中。",[10,2030,2031],{"id":2031},"主题管理器",[15,2033,2034,2035,2037,2038,2040],{},"将原本静态的 ",[19,2036,1816],{},"（资源字典）扩展成了一个功能强大的",[506,2039,2031],{},"就可以实现三个自动化，皮肤切换、",[28,2042,2044],{"className":686,"code":2043,"language":688,"meta":33,"style":33},"public class Theme : ResourceDictionary\n{\n    public Theme()\n    {\n        if (DesignerHelper.IsInDesignMode)\n        {\n            MergedDictionaries.Add(ResourceHelper.GetSkin(SkinType.Default));\n            MergedDictionaries.Add(ResourceHelper.GetTheme());\n        }\n        else\n        {\n            InitResource();\n        }\n    }\n\n    #region Skin\n\n    private SkinType _manualSkinType;\n\n    private SkinType _skin;\n\n    public virtual SkinType Skin\n    {\n        get => _skin;\n        set\n        {\n            if (_skin == value) return;\n            _skin = value;\n\n            UpdateSkin();\n        }\n    }\n\n    public static readonly DependencyProperty SkinProperty = DependencyProperty.RegisterAttached(\n        \"Skin\", typeof(SkinType), typeof(Theme), new PropertyMetadata(default(SkinType), OnSkinChanged));\n\n    private static void OnSkinChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)\n    {\n        if (d is not FrameworkElement element)\n        {\n            return;\n        }\n\n        var skin = (SkinType) e.NewValue;\n\n        var themes = new List\u003CTheme>();\n        GetAllThemes(element.Resources, ref themes);\n\n        if (themes.Count > 0)\n        {\n            foreach (var theme in themes)\n            {\n                theme.Skin = skin;\n            }\n        }\n        else\n        {\n            element.Resources.MergedDictionaries.Add(new Theme\n            {\n                Skin = skin\n            });\n        }\n    }\n\n    private static void GetAllThemes(ResourceDictionary resourceDictionary, ref List\u003CTheme> themes)\n    {\n        if (resourceDictionary is Theme theme)\n        {\n            themes.Add(theme);\n        }\n\n        \u002F\u002F we must consider it's MergedDictionaries\n        foreach (var dictionaryMergedDictionary in resourceDictionary.MergedDictionaries)\n        {\n            GetAllThemes(dictionaryMergedDictionary, ref themes);\n        }\n    }\n\n    public static void SetSkin(DependencyObject element, SkinType value)\n        => element.SetValue(SkinProperty, value);\n\n    public static SkinType GetSkin(DependencyObject element)\n        => (SkinType) element.GetValue(SkinProperty);\n\n    #endregion\n\n    #region SyncWithSystem\n\n    private bool _syncWithSystem;\n\n    public bool SyncWithSystem\n    {\n        get => _syncWithSystem;\n        set\n        {\n            _syncWithSystem = value;\n\n            if (value)\n            {\n                _manualSkinType = _skin;\n                SyncWithSystemTheme();\n\n                SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;\n            }\n            else\n            {\n                SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged;\n\n                _skin = _manualSkinType;\n                UpdateSkin();\n            }\n        }\n    }\n\n    private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)\n    {\n        if (e.Category == UserPreferenceCategory.General)\n        {\n            SyncWithSystemTheme();\n        }\n    }\n\n    private void SyncWithSystemTheme()\n    {\n        _skin = SystemHelper.DetermineIfInLightThemeMode() ? SkinType.Default : SkinType.Dark;\n        UpdateSkin();\n    }\n\n    #endregion\n\n    #region AccentColor\n\n    private Color? _accentColor;\n\n    public Color? AccentColor\n    {\n        get => _accentColor;\n        set\n        {\n            _accentColor = value;\n\n            if (value == null)\n            {\n                _precSkin = null;\n            }\n\n            UpdateSkin();\n        }\n    }\n\n    #endregion\n\n    #region Source\n\n    private Uri _source;\n\n    public new Uri Source\n    {\n        get => DesignerHelper.IsInDesignMode ? null : _source;\n        set => _source = value;\n    }\n\n    #endregion\n\n    public string Name { get; set; }\n\n    private SkinType _prevSkinType;\n\n    private ResourceDictionary _precSkin;\n\n    public virtual ResourceDictionary GetSkin(SkinType skinType)\n    {\n        if (_precSkin == null || _prevSkinType != skinType)\n        {\n            _precSkin = ResourceHelper.GetSkin(skinType);\n            _prevSkinType = skinType;\n        }\n\n        if (!SyncWithSystem)\n        {\n            if (AccentColor != null)\n            {\n                UpdateAccentColor(AccentColor.Value);\n            }\n        }\n        else\n        {\n            InteropMethods.DwmGetColorizationColor(out var color, out _);\n            UpdateAccentColor(ColorHelper.ToColor(color));\n        }\n\n        return _precSkin;\n    }\n\n    public static Theme GetTheme(string name, ResourceDictionary resourceDictionary)\n    {\n        if (string.IsNullOrEmpty(name) || resourceDictionary == null)\n        {\n            return null;\n        }\n\n        return resourceDictionary.MergedDictionaries.OfType\u003CTheme>().FirstOrDefault(item => Equals(item.Name, name));\n    }\n\n    public virtual ResourceDictionary GetTheme() => ResourceHelper.GetTheme();\n\n    private void InitResource()\n    {\n        if (DesignerHelper.IsInDesignMode)\n        {\n            return;\n        }\n\n        MergedDictionaries.Clear();\n        MergedDictionaries.Add(GetSkin(Skin));\n        MergedDictionaries.Add(GetTheme());\n    }\n\n    private void UpdateAccentColor(Color color)\n    {\n        _precSkin[ResourceToken.PrimaryColor] = color;\n        _precSkin[ResourceToken.DarkPrimaryColor] = color;\n        _precSkin[ResourceToken.TitleColor] = color;\n        _precSkin[ResourceToken.SecondaryTitleColor] = color;\n    }\n\n    private void UpdateSkin() => MergedDictionaries[0] = GetSkin(Skin);\n}\n\npublic class StandaloneTheme : Theme\n{\n    public override ResourceDictionary GetTheme() => ResourceHelper.GetStandaloneTheme();\n}\n\n",[19,2045,2046,2051,2055,2060,2064,2069,2073,2078,2083,2087,2092,2096,2101,2105,2109,2113,2118,2122,2127,2131,2136,2140,2145,2149,2154,2158,2162,2167,2172,2176,2181,2185,2189,2193,2198,2203,2207,2212,2216,2221,2225,2230,2234,2238,2243,2247,2252,2257,2262,2268,2273,2279,2284,2290,2295,2300,2305,2310,2316,2321,2327,2333,2338,2343,2348,2354,2359,2365,2370,2376,2381,2386,2392,2398,2403,2409,2414,2419,2424,2430,2436,2441,2447,2453,2458,2464,2469,2475,2480,2486,2491,2497,2502,2508,2513,2518,2524,2529,2535,2540,2546,2552,2557,2563,2568,2573,2578,2584,2589,2595,2601,2606,2611,2616,2621,2627,2632,2638,2643,2649,2654,2659,2664,2670,2675,2681,2687,2692,2697,2702,2707,2713,2718,2724,2729,2735,2740,2746,2751,2756,2762,2767,2773,2778,2784,2789,2794,2799,2804,2809,2814,2819,2824,2830,2835,2841,2846,2851,2856,2862,2868,2873,2878,2883,2888,2894,2899,2905,2910,2916,2921,2927,2932,2938,2943,2949,2955,2960,2965,2971,2976,2982,2987,2993,2998,3003,3008,3013,3019,3025,3030,3035,3041,3046,3051,3057,3062,3068,3073,3079,3084,3089,3095,3100,3105,3111,3116,3122,3127,3132,3137,3142,3147,3152,3158,3164,3170,3175,3180,3186,3191,3197,3203,3209,3215,3220,3225,3231,3236,3241,3247,3252,3258],{"__ignoreMap":33},[37,2047,2048],{"class":39,"line":40},[37,2049,2050],{},"public class Theme : ResourceDictionary\n",[37,2052,2053],{"class":39,"line":46},[37,2054,730],{},[37,2056,2057],{"class":39,"line":53},[37,2058,2059],{},"    public Theme()\n",[37,2061,2062],{"class":39,"line":59},[37,2063,935],{},[37,2065,2066],{"class":39,"line":64},[37,2067,2068],{},"        if (DesignerHelper.IsInDesignMode)\n",[37,2070,2071],{"class":39,"line":70},[37,2072,945],{},[37,2074,2075],{"class":39,"line":75},[37,2076,2077],{},"            MergedDictionaries.Add(ResourceHelper.GetSkin(SkinType.Default));\n",[37,2079,2080],{"class":39,"line":81},[37,2081,2082],{},"            MergedDictionaries.Add(ResourceHelper.GetTheme());\n",[37,2084,2085],{"class":39,"line":86},[37,2086,955],{},[37,2088,2089],{"class":39,"line":92},[37,2090,2091],{},"        else\n",[37,2093,2094],{"class":39,"line":97},[37,2095,945],{},[37,2097,2098],{"class":39,"line":103},[37,2099,2100],{},"            InitResource();\n",[37,2102,2103],{"class":39,"line":108},[37,2104,955],{},[37,2106,2107],{"class":39,"line":113},[37,2108,960],{},[37,2110,2111],{"class":39,"line":118},[37,2112,50],{"emptyLinePlaceholder":49},[37,2114,2115],{"class":39,"line":329},[37,2116,2117],{},"    #region Skin\n",[37,2119,2120],{"class":39,"line":334},[37,2121,50],{"emptyLinePlaceholder":49},[37,2123,2124],{"class":39,"line":339},[37,2125,2126],{},"    private SkinType _manualSkinType;\n",[37,2128,2129],{"class":39,"line":344},[37,2130,50],{"emptyLinePlaceholder":49},[37,2132,2133],{"class":39,"line":349},[37,2134,2135],{},"    private SkinType _skin;\n",[37,2137,2138],{"class":39,"line":355},[37,2139,50],{"emptyLinePlaceholder":49},[37,2141,2142],{"class":39,"line":360},[37,2143,2144],{},"    public virtual SkinType Skin\n",[37,2146,2147],{"class":39,"line":365},[37,2148,935],{},[37,2150,2151],{"class":39,"line":370},[37,2152,2153],{},"        get => _skin;\n",[37,2155,2156],{"class":39,"line":375},[37,2157,1910],{},[37,2159,2160],{"class":39,"line":380},[37,2161,945],{},[37,2163,2164],{"class":39,"line":386},[37,2165,2166],{},"            if (_skin == value) return;\n",[37,2168,2169],{"class":39,"line":391},[37,2170,2171],{},"            _skin = value;\n",[37,2173,2174],{"class":39,"line":396},[37,2175,50],{"emptyLinePlaceholder":49},[37,2177,2178],{"class":39,"line":401},[37,2179,2180],{},"            UpdateSkin();\n",[37,2182,2183],{"class":39,"line":406},[37,2184,955],{},[37,2186,2187],{"class":39,"line":411},[37,2188,960],{},[37,2190,2191],{"class":39,"line":416},[37,2192,50],{"emptyLinePlaceholder":49},[37,2194,2195],{"class":39,"line":421},[37,2196,2197],{},"    public static readonly DependencyProperty SkinProperty = DependencyProperty.RegisterAttached(\n",[37,2199,2200],{"class":39,"line":426},[37,2201,2202],{},"        \"Skin\", typeof(SkinType), typeof(Theme), new PropertyMetadata(default(SkinType), OnSkinChanged));\n",[37,2204,2205],{"class":39,"line":432},[37,2206,50],{"emptyLinePlaceholder":49},[37,2208,2209],{"class":39,"line":437},[37,2210,2211],{},"    private static void OnSkinChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)\n",[37,2213,2214],{"class":39,"line":442},[37,2215,935],{},[37,2217,2218],{"class":39,"line":447},[37,2219,2220],{},"        if (d is not FrameworkElement element)\n",[37,2222,2223],{"class":39,"line":452},[37,2224,945],{},[37,2226,2227],{"class":39,"line":457},[37,2228,2229],{},"            return;\n",[37,2231,2232],{"class":39,"line":463},[37,2233,955],{},[37,2235,2236],{"class":39,"line":468},[37,2237,50],{"emptyLinePlaceholder":49},[37,2239,2240],{"class":39,"line":473},[37,2241,2242],{},"        var skin = (SkinType) e.NewValue;\n",[37,2244,2245],{"class":39,"line":478},[37,2246,50],{"emptyLinePlaceholder":49},[37,2248,2249],{"class":39,"line":483},[37,2250,2251],{},"        var themes = new List\u003CTheme>();\n",[37,2253,2254],{"class":39,"line":488},[37,2255,2256],{},"        GetAllThemes(element.Resources, ref themes);\n",[37,2258,2260],{"class":39,"line":2259},48,[37,2261,50],{"emptyLinePlaceholder":49},[37,2263,2265],{"class":39,"line":2264},49,[37,2266,2267],{},"        if (themes.Count > 0)\n",[37,2269,2271],{"class":39,"line":2270},50,[37,2272,945],{},[37,2274,2276],{"class":39,"line":2275},51,[37,2277,2278],{},"            foreach (var theme in themes)\n",[37,2280,2282],{"class":39,"line":2281},52,[37,2283,1929],{},[37,2285,2287],{"class":39,"line":2286},53,[37,2288,2289],{},"                theme.Skin = skin;\n",[37,2291,2293],{"class":39,"line":2292},54,[37,2294,1944],{},[37,2296,2298],{"class":39,"line":2297},55,[37,2299,955],{},[37,2301,2303],{"class":39,"line":2302},56,[37,2304,2091],{},[37,2306,2308],{"class":39,"line":2307},57,[37,2309,945],{},[37,2311,2313],{"class":39,"line":2312},58,[37,2314,2315],{},"            element.Resources.MergedDictionaries.Add(new Theme\n",[37,2317,2319],{"class":39,"line":2318},59,[37,2320,1929],{},[37,2322,2324],{"class":39,"line":2323},60,[37,2325,2326],{},"                Skin = skin\n",[37,2328,2330],{"class":39,"line":2329},61,[37,2331,2332],{},"            });\n",[37,2334,2336],{"class":39,"line":2335},62,[37,2337,955],{},[37,2339,2341],{"class":39,"line":2340},63,[37,2342,960],{},[37,2344,2346],{"class":39,"line":2345},64,[37,2347,50],{"emptyLinePlaceholder":49},[37,2349,2351],{"class":39,"line":2350},65,[37,2352,2353],{},"    private static void GetAllThemes(ResourceDictionary resourceDictionary, ref List\u003CTheme> themes)\n",[37,2355,2357],{"class":39,"line":2356},66,[37,2358,935],{},[37,2360,2362],{"class":39,"line":2361},67,[37,2363,2364],{},"        if (resourceDictionary is Theme theme)\n",[37,2366,2368],{"class":39,"line":2367},68,[37,2369,945],{},[37,2371,2373],{"class":39,"line":2372},69,[37,2374,2375],{},"            themes.Add(theme);\n",[37,2377,2379],{"class":39,"line":2378},70,[37,2380,955],{},[37,2382,2384],{"class":39,"line":2383},71,[37,2385,50],{"emptyLinePlaceholder":49},[37,2387,2389],{"class":39,"line":2388},72,[37,2390,2391],{},"        \u002F\u002F we must consider it's MergedDictionaries\n",[37,2393,2395],{"class":39,"line":2394},73,[37,2396,2397],{},"        foreach (var dictionaryMergedDictionary in resourceDictionary.MergedDictionaries)\n",[37,2399,2401],{"class":39,"line":2400},74,[37,2402,945],{},[37,2404,2406],{"class":39,"line":2405},75,[37,2407,2408],{},"            GetAllThemes(dictionaryMergedDictionary, ref themes);\n",[37,2410,2412],{"class":39,"line":2411},76,[37,2413,955],{},[37,2415,2417],{"class":39,"line":2416},77,[37,2418,960],{},[37,2420,2422],{"class":39,"line":2421},78,[37,2423,50],{"emptyLinePlaceholder":49},[37,2425,2427],{"class":39,"line":2426},79,[37,2428,2429],{},"    public static void SetSkin(DependencyObject element, SkinType value)\n",[37,2431,2433],{"class":39,"line":2432},80,[37,2434,2435],{},"        => element.SetValue(SkinProperty, value);\n",[37,2437,2439],{"class":39,"line":2438},81,[37,2440,50],{"emptyLinePlaceholder":49},[37,2442,2444],{"class":39,"line":2443},82,[37,2445,2446],{},"    public static SkinType GetSkin(DependencyObject element)\n",[37,2448,2450],{"class":39,"line":2449},83,[37,2451,2452],{},"        => (SkinType) element.GetValue(SkinProperty);\n",[37,2454,2456],{"class":39,"line":2455},84,[37,2457,50],{"emptyLinePlaceholder":49},[37,2459,2461],{"class":39,"line":2460},85,[37,2462,2463],{},"    #endregion\n",[37,2465,2467],{"class":39,"line":2466},86,[37,2468,50],{"emptyLinePlaceholder":49},[37,2470,2472],{"class":39,"line":2471},87,[37,2473,2474],{},"    #region SyncWithSystem\n",[37,2476,2478],{"class":39,"line":2477},88,[37,2479,50],{"emptyLinePlaceholder":49},[37,2481,2483],{"class":39,"line":2482},89,[37,2484,2485],{},"    private bool _syncWithSystem;\n",[37,2487,2489],{"class":39,"line":2488},90,[37,2490,50],{"emptyLinePlaceholder":49},[37,2492,2494],{"class":39,"line":2493},91,[37,2495,2496],{},"    public bool SyncWithSystem\n",[37,2498,2500],{"class":39,"line":2499},92,[37,2501,935],{},[37,2503,2505],{"class":39,"line":2504},93,[37,2506,2507],{},"        get => _syncWithSystem;\n",[37,2509,2511],{"class":39,"line":2510},94,[37,2512,1910],{},[37,2514,2516],{"class":39,"line":2515},95,[37,2517,945],{},[37,2519,2521],{"class":39,"line":2520},96,[37,2522,2523],{},"            _syncWithSystem = value;\n",[37,2525,2527],{"class":39,"line":2526},97,[37,2528,50],{"emptyLinePlaceholder":49},[37,2530,2532],{"class":39,"line":2531},98,[37,2533,2534],{},"            if (value)\n",[37,2536,2538],{"class":39,"line":2537},99,[37,2539,1929],{},[37,2541,2543],{"class":39,"line":2542},100,[37,2544,2545],{},"                _manualSkinType = _skin;\n",[37,2547,2549],{"class":39,"line":2548},101,[37,2550,2551],{},"                SyncWithSystemTheme();\n",[37,2553,2555],{"class":39,"line":2554},102,[37,2556,50],{"emptyLinePlaceholder":49},[37,2558,2560],{"class":39,"line":2559},103,[37,2561,2562],{},"                SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;\n",[37,2564,2566],{"class":39,"line":2565},104,[37,2567,1944],{},[37,2569,2571],{"class":39,"line":2570},105,[37,2572,1980],{},[37,2574,2576],{"class":39,"line":2575},106,[37,2577,1929],{},[37,2579,2581],{"class":39,"line":2580},107,[37,2582,2583],{},"                SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged;\n",[37,2585,2587],{"class":39,"line":2586},108,[37,2588,50],{"emptyLinePlaceholder":49},[37,2590,2592],{"class":39,"line":2591},109,[37,2593,2594],{},"                _skin = _manualSkinType;\n",[37,2596,2598],{"class":39,"line":2597},110,[37,2599,2600],{},"                UpdateSkin();\n",[37,2602,2604],{"class":39,"line":2603},111,[37,2605,1944],{},[37,2607,2609],{"class":39,"line":2608},112,[37,2610,955],{},[37,2612,2614],{"class":39,"line":2613},113,[37,2615,960],{},[37,2617,2619],{"class":39,"line":2618},114,[37,2620,50],{"emptyLinePlaceholder":49},[37,2622,2624],{"class":39,"line":2623},115,[37,2625,2626],{},"    private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)\n",[37,2628,2630],{"class":39,"line":2629},116,[37,2631,935],{},[37,2633,2635],{"class":39,"line":2634},117,[37,2636,2637],{},"        if (e.Category == UserPreferenceCategory.General)\n",[37,2639,2641],{"class":39,"line":2640},118,[37,2642,945],{},[37,2644,2646],{"class":39,"line":2645},119,[37,2647,2648],{},"            SyncWithSystemTheme();\n",[37,2650,2652],{"class":39,"line":2651},120,[37,2653,955],{},[37,2655,2657],{"class":39,"line":2656},121,[37,2658,960],{},[37,2660,2662],{"class":39,"line":2661},122,[37,2663,50],{"emptyLinePlaceholder":49},[37,2665,2667],{"class":39,"line":2666},123,[37,2668,2669],{},"    private void SyncWithSystemTheme()\n",[37,2671,2673],{"class":39,"line":2672},124,[37,2674,935],{},[37,2676,2678],{"class":39,"line":2677},125,[37,2679,2680],{},"        _skin = SystemHelper.DetermineIfInLightThemeMode() ? SkinType.Default : SkinType.Dark;\n",[37,2682,2684],{"class":39,"line":2683},126,[37,2685,2686],{},"        UpdateSkin();\n",[37,2688,2690],{"class":39,"line":2689},127,[37,2691,960],{},[37,2693,2695],{"class":39,"line":2694},128,[37,2696,50],{"emptyLinePlaceholder":49},[37,2698,2700],{"class":39,"line":2699},129,[37,2701,2463],{},[37,2703,2705],{"class":39,"line":2704},130,[37,2706,50],{"emptyLinePlaceholder":49},[37,2708,2710],{"class":39,"line":2709},131,[37,2711,2712],{},"    #region AccentColor\n",[37,2714,2716],{"class":39,"line":2715},132,[37,2717,50],{"emptyLinePlaceholder":49},[37,2719,2721],{"class":39,"line":2720},133,[37,2722,2723],{},"    private Color? _accentColor;\n",[37,2725,2727],{"class":39,"line":2726},134,[37,2728,50],{"emptyLinePlaceholder":49},[37,2730,2732],{"class":39,"line":2731},135,[37,2733,2734],{},"    public Color? AccentColor\n",[37,2736,2738],{"class":39,"line":2737},136,[37,2739,935],{},[37,2741,2743],{"class":39,"line":2742},137,[37,2744,2745],{},"        get => _accentColor;\n",[37,2747,2749],{"class":39,"line":2748},138,[37,2750,1910],{},[37,2752,2754],{"class":39,"line":2753},139,[37,2755,945],{},[37,2757,2759],{"class":39,"line":2758},140,[37,2760,2761],{},"            _accentColor = value;\n",[37,2763,2765],{"class":39,"line":2764},141,[37,2766,50],{"emptyLinePlaceholder":49},[37,2768,2770],{"class":39,"line":2769},142,[37,2771,2772],{},"            if (value == null)\n",[37,2774,2776],{"class":39,"line":2775},143,[37,2777,1929],{},[37,2779,2781],{"class":39,"line":2780},144,[37,2782,2783],{},"                _precSkin = null;\n",[37,2785,2787],{"class":39,"line":2786},145,[37,2788,1944],{},[37,2790,2792],{"class":39,"line":2791},146,[37,2793,50],{"emptyLinePlaceholder":49},[37,2795,2797],{"class":39,"line":2796},147,[37,2798,2180],{},[37,2800,2802],{"class":39,"line":2801},148,[37,2803,955],{},[37,2805,2807],{"class":39,"line":2806},149,[37,2808,960],{},[37,2810,2812],{"class":39,"line":2811},150,[37,2813,50],{"emptyLinePlaceholder":49},[37,2815,2817],{"class":39,"line":2816},151,[37,2818,2463],{},[37,2820,2822],{"class":39,"line":2821},152,[37,2823,50],{"emptyLinePlaceholder":49},[37,2825,2827],{"class":39,"line":2826},153,[37,2828,2829],{},"    #region Source\n",[37,2831,2833],{"class":39,"line":2832},154,[37,2834,50],{"emptyLinePlaceholder":49},[37,2836,2838],{"class":39,"line":2837},155,[37,2839,2840],{},"    private Uri _source;\n",[37,2842,2844],{"class":39,"line":2843},156,[37,2845,50],{"emptyLinePlaceholder":49},[37,2847,2849],{"class":39,"line":2848},157,[37,2850,1896],{},[37,2852,2854],{"class":39,"line":2853},158,[37,2855,935],{},[37,2857,2859],{"class":39,"line":2858},159,[37,2860,2861],{},"        get => DesignerHelper.IsInDesignMode ? null : _source;\n",[37,2863,2865],{"class":39,"line":2864},160,[37,2866,2867],{},"        set => _source = value;\n",[37,2869,2871],{"class":39,"line":2870},161,[37,2872,960],{},[37,2874,2876],{"class":39,"line":2875},162,[37,2877,50],{"emptyLinePlaceholder":49},[37,2879,2881],{"class":39,"line":2880},163,[37,2882,2463],{},[37,2884,2886],{"class":39,"line":2885},164,[37,2887,50],{"emptyLinePlaceholder":49},[37,2889,2891],{"class":39,"line":2890},165,[37,2892,2893],{},"    public string Name { get; set; }\n",[37,2895,2897],{"class":39,"line":2896},166,[37,2898,50],{"emptyLinePlaceholder":49},[37,2900,2902],{"class":39,"line":2901},167,[37,2903,2904],{},"    private SkinType _prevSkinType;\n",[37,2906,2908],{"class":39,"line":2907},168,[37,2909,50],{"emptyLinePlaceholder":49},[37,2911,2913],{"class":39,"line":2912},169,[37,2914,2915],{},"    private ResourceDictionary _precSkin;\n",[37,2917,2919],{"class":39,"line":2918},170,[37,2920,50],{"emptyLinePlaceholder":49},[37,2922,2924],{"class":39,"line":2923},171,[37,2925,2926],{},"    public virtual ResourceDictionary GetSkin(SkinType skinType)\n",[37,2928,2930],{"class":39,"line":2929},172,[37,2931,935],{},[37,2933,2935],{"class":39,"line":2934},173,[37,2936,2937],{},"        if (_precSkin == null || _prevSkinType != skinType)\n",[37,2939,2941],{"class":39,"line":2940},174,[37,2942,945],{},[37,2944,2946],{"class":39,"line":2945},175,[37,2947,2948],{},"            _precSkin = ResourceHelper.GetSkin(skinType);\n",[37,2950,2952],{"class":39,"line":2951},176,[37,2953,2954],{},"            _prevSkinType = skinType;\n",[37,2956,2958],{"class":39,"line":2957},177,[37,2959,955],{},[37,2961,2963],{"class":39,"line":2962},178,[37,2964,50],{"emptyLinePlaceholder":49},[37,2966,2968],{"class":39,"line":2967},179,[37,2969,2970],{},"        if (!SyncWithSystem)\n",[37,2972,2974],{"class":39,"line":2973},180,[37,2975,945],{},[37,2977,2979],{"class":39,"line":2978},181,[37,2980,2981],{},"            if (AccentColor != null)\n",[37,2983,2985],{"class":39,"line":2984},182,[37,2986,1929],{},[37,2988,2990],{"class":39,"line":2989},183,[37,2991,2992],{},"                UpdateAccentColor(AccentColor.Value);\n",[37,2994,2996],{"class":39,"line":2995},184,[37,2997,1944],{},[37,2999,3001],{"class":39,"line":3000},185,[37,3002,955],{},[37,3004,3006],{"class":39,"line":3005},186,[37,3007,2091],{},[37,3009,3011],{"class":39,"line":3010},187,[37,3012,945],{},[37,3014,3016],{"class":39,"line":3015},188,[37,3017,3018],{},"            InteropMethods.DwmGetColorizationColor(out var color, out _);\n",[37,3020,3022],{"class":39,"line":3021},189,[37,3023,3024],{},"            UpdateAccentColor(ColorHelper.ToColor(color));\n",[37,3026,3028],{"class":39,"line":3027},190,[37,3029,955],{},[37,3031,3033],{"class":39,"line":3032},191,[37,3034,50],{"emptyLinePlaceholder":49},[37,3036,3038],{"class":39,"line":3037},192,[37,3039,3040],{},"        return _precSkin;\n",[37,3042,3044],{"class":39,"line":3043},193,[37,3045,960],{},[37,3047,3049],{"class":39,"line":3048},194,[37,3050,50],{"emptyLinePlaceholder":49},[37,3052,3054],{"class":39,"line":3053},195,[37,3055,3056],{},"    public static Theme GetTheme(string name, ResourceDictionary resourceDictionary)\n",[37,3058,3060],{"class":39,"line":3059},196,[37,3061,935],{},[37,3063,3065],{"class":39,"line":3064},197,[37,3066,3067],{},"        if (string.IsNullOrEmpty(name) || resourceDictionary == null)\n",[37,3069,3071],{"class":39,"line":3070},198,[37,3072,945],{},[37,3074,3076],{"class":39,"line":3075},199,[37,3077,3078],{},"            return null;\n",[37,3080,3082],{"class":39,"line":3081},200,[37,3083,955],{},[37,3085,3087],{"class":39,"line":3086},201,[37,3088,50],{"emptyLinePlaceholder":49},[37,3090,3092],{"class":39,"line":3091},202,[37,3093,3094],{},"        return resourceDictionary.MergedDictionaries.OfType\u003CTheme>().FirstOrDefault(item => Equals(item.Name, name));\n",[37,3096,3098],{"class":39,"line":3097},203,[37,3099,960],{},[37,3101,3103],{"class":39,"line":3102},204,[37,3104,50],{"emptyLinePlaceholder":49},[37,3106,3108],{"class":39,"line":3107},205,[37,3109,3110],{},"    public virtual ResourceDictionary GetTheme() => ResourceHelper.GetTheme();\n",[37,3112,3114],{"class":39,"line":3113},206,[37,3115,50],{"emptyLinePlaceholder":49},[37,3117,3119],{"class":39,"line":3118},207,[37,3120,3121],{},"    private void InitResource()\n",[37,3123,3125],{"class":39,"line":3124},208,[37,3126,935],{},[37,3128,3130],{"class":39,"line":3129},209,[37,3131,2068],{},[37,3133,3135],{"class":39,"line":3134},210,[37,3136,945],{},[37,3138,3140],{"class":39,"line":3139},211,[37,3141,2229],{},[37,3143,3145],{"class":39,"line":3144},212,[37,3146,955],{},[37,3148,3150],{"class":39,"line":3149},213,[37,3151,50],{"emptyLinePlaceholder":49},[37,3153,3155],{"class":39,"line":3154},214,[37,3156,3157],{},"        MergedDictionaries.Clear();\n",[37,3159,3161],{"class":39,"line":3160},215,[37,3162,3163],{},"        MergedDictionaries.Add(GetSkin(Skin));\n",[37,3165,3167],{"class":39,"line":3166},216,[37,3168,3169],{},"        MergedDictionaries.Add(GetTheme());\n",[37,3171,3173],{"class":39,"line":3172},217,[37,3174,960],{},[37,3176,3178],{"class":39,"line":3177},218,[37,3179,50],{"emptyLinePlaceholder":49},[37,3181,3183],{"class":39,"line":3182},219,[37,3184,3185],{},"    private void UpdateAccentColor(Color color)\n",[37,3187,3189],{"class":39,"line":3188},220,[37,3190,935],{},[37,3192,3194],{"class":39,"line":3193},221,[37,3195,3196],{},"        _precSkin[ResourceToken.PrimaryColor] = color;\n",[37,3198,3200],{"class":39,"line":3199},222,[37,3201,3202],{},"        _precSkin[ResourceToken.DarkPrimaryColor] = color;\n",[37,3204,3206],{"class":39,"line":3205},223,[37,3207,3208],{},"        _precSkin[ResourceToken.TitleColor] = color;\n",[37,3210,3212],{"class":39,"line":3211},224,[37,3213,3214],{},"        _precSkin[ResourceToken.SecondaryTitleColor] = color;\n",[37,3216,3218],{"class":39,"line":3217},225,[37,3219,960],{},[37,3221,3223],{"class":39,"line":3222},226,[37,3224,50],{"emptyLinePlaceholder":49},[37,3226,3228],{"class":39,"line":3227},227,[37,3229,3230],{},"    private void UpdateSkin() => MergedDictionaries[0] = GetSkin(Skin);\n",[37,3232,3234],{"class":39,"line":3233},228,[37,3235,755],{},[37,3237,3239],{"class":39,"line":3238},229,[37,3240,50],{"emptyLinePlaceholder":49},[37,3242,3244],{"class":39,"line":3243},230,[37,3245,3246],{},"public class StandaloneTheme : Theme\n",[37,3248,3250],{"class":39,"line":3249},231,[37,3251,730],{},[37,3253,3255],{"class":39,"line":3254},232,[37,3256,3257],{},"    public override ResourceDictionary GetTheme() => ResourceHelper.GetStandaloneTheme();\n",[37,3259,3261],{"class":39,"line":3260},233,[37,3262,755],{},[15,3264,3265],{},"这里和上一个文件不同的地方在于，这里主要是主题的相关策略，就比如说切换和控制之类的。",[10,3267,3268],{"id":3268},"运行时汇总",[15,3270,3271],{},"![[Pasted image 20260406174534.png]]",[15,3273,3274,3275,3278,3279,3281],{},"Theme.xaml是一份极为庞大的文件，",[19,3276,3277],{},"Themes\u002FStyles"," 是“源码拆分层”，",[19,3280,616],{}," 是“运行时汇总产物层”。",[15,3283,3284],{},"这是为了同时兼具方便人维护和方便运行时加载的功能，运行时一般只加载：",[126,3286,3287,3297,3315,3321],{},[129,3288,3289,3292,3293,3296],{},[19,3290,3291],{},"pack:\u002F\u002Fapplication:,,,\u002FHandyControl;component\u002FThemes\u002FTheme.xaml","\n这点在 ",[19,3294,3295],{},"ResourceHelper.GetTheme()"," 里就能看到。",[129,3298,3299,1127,3302,3305,3306,233,3309,233,3312,1194],{},[19,3300,3301],{},"Theme_GE45.txt",[19,3303,3304],{},"Theme_40.txt"," 明确列出了要合并的文件清单（包含 ",[19,3307,3308],{},"Basic\u002F*",[19,3310,3311],{},"Styles\u002F*",[19,3313,3314],{},"Styles\u002FBase\u002F*",[129,3316,3317,3320],{},[19,3318,3319],{},"Themes\u002FXamlCombine.exe"," 存在，说明有“把拆分样式合并成 Theme.xaml”的构建流程",[129,3322,3323,3325],{},[19,3324,616],{}," 顶部也写了 generated 注释（自动生成）",[3327,3328,3329],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":33,"searchDepth":46,"depth":46,"links":3331},[3332,3333,3334,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353],{"id":12,"depth":46,"text":13},{"id":243,"depth":46,"text":244},{"id":525,"depth":46,"text":526,"children":3335},[3336,3337,3339,3340,3341,3342],{"id":610,"depth":53,"text":611},{"id":780,"depth":53,"text":3338},"事件 -> 命令（Interactivity 桥接）",{"id":870,"depth":53,"text":871},{"id":973,"depth":53,"text":974},{"id":1133,"depth":53,"text":1134},{"id":1316,"depth":53,"text":1317},{"id":1377,"depth":46,"text":1378},{"id":1387,"depth":46,"text":1388},{"id":1475,"depth":46,"text":1476},{"id":1591,"depth":46,"text":1592},{"id":1614,"depth":46,"text":1615},{"id":1673,"depth":46,"text":1674},{"id":1690,"depth":46,"text":1691},{"id":1711,"depth":46,"text":1712},{"id":1795,"depth":46,"text":1795},{"id":2031,"depth":46,"text":2031},{"id":3268,"depth":46,"text":3268},"md",{},"\u002Fcsharp\u002Fwpf\u002Fhandycontrol\u002Fthemes",{"description":33},"csharp\u002FWPF\u002FHandyControl\u002FThemes","rs-RB1M8KAHgn3LiaBSucQzYpjTBtyfCNPQmL_z4W0I",1791042465312]