[{"data":1,"prerenderedAt":1922},["ShallowReactive",2],{"page-\u002Fcsharp\u002Fwpf\u002Fwpf和dll扩展加载":3},{"id":4,"title":5,"body":6,"description":143,"extension":1916,"meta":1917,"navigation":166,"path":1918,"seo":1919,"stem":1920,"__hash__":1921},"content\u002Fcsharp\u002FWPF\u002Fwpf和dll扩展加载.md","WPF和DLL扩展加载",{"type":7,"value":8,"toc":1867},"minimark",[9,13,17,70,73,77,82,94,98,109,113,127,129,133,137,197,201,212,225,235,272,276,285,287,291,295,306,310,335,339,350,354,488,490,494,498,541,545,559,563,574,578,616,618,622,626,637,641,684,688,699,701,705,709,769,773,784,788,799,801,805,809,900,904,915,919,930,932,936,940,951,955,965,969,1051,1055,1066,1070,1081,1083,1086,1089,1092,1095,1098,1336,1339,1344,1347,1568,1571,1630,1633,1857,1863],[10,11,5],"h1",{"id":12},"wpf和dll扩展加载",[14,15,16],"h2",{"id":16},"目录",[18,19,20,28,34,40,46,52,58,64],"ol",{},[21,22,23],"li",{},[24,25,27],"a",{"href":26},"#1-dll%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5","DLL基础概念",[21,29,30],{},[24,31,33],{"href":32},"#2-wpf%E4%B8%AD%E7%9A%84dll%E5%8A%A0%E8%BD%BD%E6%9C%BA%E5%88%B6","WPF中的DLL加载机制",[21,35,36],{},[24,37,39],{"href":38},"#3-%E7%A8%8B%E5%BA%8F%E9%9B%86%E5%8F%8D%E5%B0%84%E5%8A%A0%E8%BD%BD","程序集反射加载",[21,41,42],{},[24,43,45],{"href":44},"#4-%E6%8F%92%E4%BB%B6%E5%8C%96%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1","插件化架构设计",[21,47,48],{},[24,49,51],{"href":50},"#5-%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E4%B8%8E%E5%8D%B8%E8%BD%BD","动态加载与卸载",[21,53,54],{},[24,55,57],{"href":56},"#6-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%E4%B8%8E%E6%89%A9%E5%B1%95","依赖注入与扩展",[21,59,60],{},[24,61,63],{"href":62},"#7-%E5%AE%9E%E9%99%85%E5%BA%94%E7%94%A8%E6%A1%88%E4%BE%8B","实际应用案例",[21,65,66],{},[24,67,69],{"href":68},"#8-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E4%B8%8E%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9","最佳实践与注意事项",[71,72],"hr",{},[14,74,76],{"id":75},"_1-dll基础概念","1. DLL基础概念",[78,79,81],"h3",{"id":80},"_11-什么是dll","1.1 什么是DLL",[83,84,85,88,91],"ul",{},[21,86,87],{},"动态链接库的定义",[21,89,90],{},"DLL与静态库的区别",[21,92,93],{},".NET程序集的概念",[78,95,97],{"id":96},"_12-dll的类型","1.2 DLL的类型",[83,99,100,103,106],{},[21,101,102],{},"托管DLL（.NET程序集）",[21,104,105],{},"非托管DLL（Win32）",[21,107,108],{},"混合模式DLL",[78,110,112],{"id":111},"_13-dll的优势","1.3 DLL的优势",[83,114,115,118,121,124],{},[21,116,117],{},"代码复用",[21,119,120],{},"模块化开发",[21,122,123],{},"动态更新",[21,125,126],{},"内存优化",[71,128],{},[14,130,132],{"id":131},"_2-wpf中的dll加载机制","2. WPF中的DLL加载机制",[78,134,136],{"id":135},"_21-程序集加载方式","2.1 程序集加载方式",[138,139,144],"pre",{"className":140,"code":141,"language":142,"meta":143,"style":143},"language-csharp shiki shiki-themes github-light github-dark","\u002F\u002F 静态加载\nAssembly assembly = Assembly.LoadFrom(\"path\u002Fto\u002Fdll\");\n\n\u002F\u002F 动态加载\nAssembly assembly = Assembly.LoadFile(\"path\u002Fto\u002Fdll\");\n\n\u002F\u002F 反射加载\nType type = assembly.GetType(\"Namespace.ClassName\");\n","csharp","",[145,146,147,155,161,168,174,180,185,191],"code",{"__ignoreMap":143},[148,149,152],"span",{"class":150,"line":151},"line",1,[148,153,154],{},"\u002F\u002F 静态加载\n",[148,156,158],{"class":150,"line":157},2,[148,159,160],{},"Assembly assembly = Assembly.LoadFrom(\"path\u002Fto\u002Fdll\");\n",[148,162,164],{"class":150,"line":163},3,[148,165,167],{"emptyLinePlaceholder":166},true,"\n",[148,169,171],{"class":150,"line":170},4,[148,172,173],{},"\u002F\u002F 动态加载\n",[148,175,177],{"class":150,"line":176},5,[148,178,179],{},"Assembly assembly = Assembly.LoadFile(\"path\u002Fto\u002Fdll\");\n",[148,181,183],{"class":150,"line":182},6,[148,184,167],{"emptyLinePlaceholder":166},[148,186,188],{"class":150,"line":187},7,[148,189,190],{},"\u002F\u002F 反射加载\n",[148,192,194],{"class":150,"line":193},8,[148,195,196],{},"Type type = assembly.GetType(\"Namespace.ClassName\");\n",[78,198,200],{"id":199},"_22-appdomain与程序集隔离","2.2 AppDomain与程序集隔离",[83,202,203,206,209],{},[21,204,205],{},"AppDomain的概念",[21,207,208],{},"程序集隔离机制",[21,210,211],{},"跨域调用",[213,214,215,216,220,221,224],"p",{},"在 .NET 框架中，",[217,218,219],"strong",{},"AppDomain"," (应用程序域) 是一个重要的概念，它提供了一种在",[217,222,223],{},"单个进程内隔离应用程序或组件的方式","。你可以把它想象成一个轻量级的“沙盒”。",[213,226,227,230,231,234],{},[217,228,229],{},"程序集隔离","指的是将不同的程序集（.dll 或 .exe 文件）加载到",[217,232,233],{},"相互独立的 AppDomain"," 中，从而实现它们之间的隔离。这种隔离带来的主要好处有：",[83,236,237,243,257,263],{},[21,238,239,242],{},[217,240,241],{},"错误隔离："," 一个 AppDomain 中的代码如果抛出未处理的异常，它只会影响到该 AppDomain，而不会导致整个进程崩溃。这使得你可以更健壮地运行第三方代码或插件。",[21,244,245,248,249,252,253,256],{},[217,246,247],{},"卸载隔离："," 程序集",[217,250,251],{},"一旦被加载到 AppDomain 中","，就无法轻易地从内存中卸载。",[217,254,255],{},"但通过卸载整个 AppDomain，可以有效地释放其加载的所有程序集和资源。这对于需要动态加载和卸载插件或组件的应用程序非常有用","。",[21,258,259,262],{},[217,260,261],{},"配置隔离："," 每个 AppDomain 都有自己的配置，例如应用程序设置、权限集等。这使得在同一个进程中运行不同配置的应用程序成为可能。",[21,264,265,268,269,256],{},[217,266,267],{},"资源隔离："," 不同的 AppDomain ",[217,270,271],{},"拥有各自的静态变量和资源，避免了相互干扰",[78,273,275],{"id":274},"_23-程序集解析事件","2.3 程序集解析事件",[138,277,279],{"className":140,"code":278,"language":142,"meta":143,"style":143},"AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;\n",[145,280,281],{"__ignoreMap":143},[148,282,283],{"class":150,"line":151},[148,284,278],{},[71,286],{},[14,288,290],{"id":289},"_3-程序集反射加载","3. 程序集反射加载",[78,292,294],{"id":293},"_31-反射基础","3.1 反射基础",[83,296,297,300,303],{},[21,298,299],{},"Type类的使用",[21,301,302],{},"获取类型信息",[21,304,305],{},"创建实例",[78,307,309],{"id":308},"_32-动态类型发现","3.2 动态类型发现",[138,311,313],{"className":140,"code":312,"language":142,"meta":143,"style":143},"\u002F\u002F 扫描程序集中的所有类型\nvar types = assembly.GetTypes()\n    .Where(t => t.GetInterfaces().Contains(typeof(IPlugin)))\n    .ToList();\n",[145,314,315,320,325,330],{"__ignoreMap":143},[148,316,317],{"class":150,"line":151},[148,318,319],{},"\u002F\u002F 扫描程序集中的所有类型\n",[148,321,322],{"class":150,"line":157},[148,323,324],{},"var types = assembly.GetTypes()\n",[148,326,327],{"class":150,"line":163},[148,328,329],{},"    .Where(t => t.GetInterfaces().Contains(typeof(IPlugin)))\n",[148,331,332],{"class":150,"line":170},[148,333,334],{},"    .ToList();\n",[78,336,338],{"id":337},"_33-接口驱动的扩展","3.3 接口驱动的扩展",[83,340,341,344,347],{},[21,342,343],{},"定义扩展接口",[21,345,346],{},"实现扩展发现",[21,348,349],{},"动态实例化",[78,351,353],{"id":352},"_34-实际应用示例","3.4 实际应用示例",[138,355,357],{"className":140,"code":356,"language":142,"meta":143,"style":143},"public class PluginManager\n{\n    public List\u003CIPlugin> LoadPlugins(string directory)\n    {\n        var plugins = new List\u003CIPlugin>();\n        var dllFiles = Directory.GetFiles(directory, \"*.dll\");\n        \n        foreach (var dll in dllFiles)\n        {\n            var assembly = Assembly.LoadFrom(dll);\n            var pluginTypes = assembly.GetTypes()\n                .Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface);\n                \n            foreach (var type in pluginTypes)\n            {\n                var plugin = (IPlugin)Activator.CreateInstance(type);\n                plugins.Add(plugin);\n            }\n        }\n        \n        return plugins;\n    }\n}\n",[145,358,359,364,369,374,379,384,389,394,399,405,411,417,423,429,435,441,447,453,459,465,470,476,482],{"__ignoreMap":143},[148,360,361],{"class":150,"line":151},[148,362,363],{},"public class PluginManager\n",[148,365,366],{"class":150,"line":157},[148,367,368],{},"{\n",[148,370,371],{"class":150,"line":163},[148,372,373],{},"    public List\u003CIPlugin> LoadPlugins(string directory)\n",[148,375,376],{"class":150,"line":170},[148,377,378],{},"    {\n",[148,380,381],{"class":150,"line":176},[148,382,383],{},"        var plugins = new List\u003CIPlugin>();\n",[148,385,386],{"class":150,"line":182},[148,387,388],{},"        var dllFiles = Directory.GetFiles(directory, \"*.dll\");\n",[148,390,391],{"class":150,"line":187},[148,392,393],{},"        \n",[148,395,396],{"class":150,"line":193},[148,397,398],{},"        foreach (var dll in dllFiles)\n",[148,400,402],{"class":150,"line":401},9,[148,403,404],{},"        {\n",[148,406,408],{"class":150,"line":407},10,[148,409,410],{},"            var assembly = Assembly.LoadFrom(dll);\n",[148,412,414],{"class":150,"line":413},11,[148,415,416],{},"            var pluginTypes = assembly.GetTypes()\n",[148,418,420],{"class":150,"line":419},12,[148,421,422],{},"                .Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface);\n",[148,424,426],{"class":150,"line":425},13,[148,427,428],{},"                \n",[148,430,432],{"class":150,"line":431},14,[148,433,434],{},"            foreach (var type in pluginTypes)\n",[148,436,438],{"class":150,"line":437},15,[148,439,440],{},"            {\n",[148,442,444],{"class":150,"line":443},16,[148,445,446],{},"                var plugin = (IPlugin)Activator.CreateInstance(type);\n",[148,448,450],{"class":150,"line":449},17,[148,451,452],{},"                plugins.Add(plugin);\n",[148,454,456],{"class":150,"line":455},18,[148,457,458],{},"            }\n",[148,460,462],{"class":150,"line":461},19,[148,463,464],{},"        }\n",[148,466,468],{"class":150,"line":467},20,[148,469,393],{},[148,471,473],{"class":150,"line":472},21,[148,474,475],{},"        return plugins;\n",[148,477,479],{"class":150,"line":478},22,[148,480,481],{},"    }\n",[148,483,485],{"class":150,"line":484},23,[148,486,487],{},"}\n",[71,489],{},[14,491,493],{"id":492},"_4-插件化架构设计","4. 插件化架构设计",[78,495,497],{"id":496},"_41-插件接口设计","4.1 插件接口设计",[138,499,501],{"className":140,"code":500,"language":142,"meta":143,"style":143},"public interface IPlugin\n{\n    string Name { get; }\n    string Version { get; }\n    void Initialize();\n    void Execute();\n    void Dispose();\n}\n",[145,502,503,508,512,517,522,527,532,537],{"__ignoreMap":143},[148,504,505],{"class":150,"line":151},[148,506,507],{},"public interface IPlugin\n",[148,509,510],{"class":150,"line":157},[148,511,368],{},[148,513,514],{"class":150,"line":163},[148,515,516],{},"    string Name { get; }\n",[148,518,519],{"class":150,"line":170},[148,520,521],{},"    string Version { get; }\n",[148,523,524],{"class":150,"line":176},[148,525,526],{},"    void Initialize();\n",[148,528,529],{"class":150,"line":182},[148,530,531],{},"    void Execute();\n",[148,533,534],{"class":150,"line":187},[148,535,536],{},"    void Dispose();\n",[148,538,539],{"class":150,"line":193},[148,540,487],{},[78,542,544],{"id":543},"_42-插件生命周期管理","4.2 插件生命周期管理",[83,546,547,550,553,556],{},[21,548,549],{},"插件加载",[21,551,552],{},"插件初始化",[21,554,555],{},"插件执行",[21,557,558],{},"插件卸载",[78,560,562],{"id":561},"_43-插件通信机制","4.3 插件通信机制",[83,564,565,568,571],{},[21,566,567],{},"事件总线",[21,569,570],{},"消息传递",[21,572,573],{},"共享数据",[78,575,577],{"id":576},"_44-插件配置管理","4.4 插件配置管理",[138,579,581],{"className":140,"code":580,"language":142,"meta":143,"style":143},"public class PluginConfiguration\n{\n    public string Name { get; set; }\n    public string AssemblyPath { get; set; }\n    public bool Enabled { get; set; }\n    public Dictionary\u003Cstring, object> Settings { get; set; }\n}\n",[145,582,583,588,592,597,602,607,612],{"__ignoreMap":143},[148,584,585],{"class":150,"line":151},[148,586,587],{},"public class PluginConfiguration\n",[148,589,590],{"class":150,"line":157},[148,591,368],{},[148,593,594],{"class":150,"line":163},[148,595,596],{},"    public string Name { get; set; }\n",[148,598,599],{"class":150,"line":170},[148,600,601],{},"    public string AssemblyPath { get; set; }\n",[148,603,604],{"class":150,"line":176},[148,605,606],{},"    public bool Enabled { get; set; }\n",[148,608,609],{"class":150,"line":182},[148,610,611],{},"    public Dictionary\u003Cstring, object> Settings { get; set; }\n",[148,613,614],{"class":150,"line":187},[148,615,487],{},[71,617],{},[14,619,621],{"id":620},"_5-动态加载与卸载","5. 动态加载与卸载",[78,623,625],{"id":624},"_51-assemblyloadfrom-vs-assemblyloadfile","5.1 Assembly.LoadFrom vs Assembly.LoadFile",[83,627,628,631,634],{},[21,629,630],{},"区别与使用场景",[21,632,633],{},"性能考虑",[21,635,636],{},"依赖解析",[78,638,640],{"id":639},"_52-程序集卸载","5.2 程序集卸载",[138,642,644],{"className":140,"code":643,"language":142,"meta":143,"style":143},"\u002F\u002F 创建新的AppDomain\nAppDomain pluginDomain = AppDomain.CreateDomain(\"PluginDomain\");\n\n\u002F\u002F 在插件域中加载程序集\npluginDomain.Load(assemblyName);\n\n\u002F\u002F 卸载插件域\nAppDomain.Unload(pluginDomain);\n",[145,645,646,651,656,660,665,670,674,679],{"__ignoreMap":143},[148,647,648],{"class":150,"line":151},[148,649,650],{},"\u002F\u002F 创建新的AppDomain\n",[148,652,653],{"class":150,"line":157},[148,654,655],{},"AppDomain pluginDomain = AppDomain.CreateDomain(\"PluginDomain\");\n",[148,657,658],{"class":150,"line":163},[148,659,167],{"emptyLinePlaceholder":166},[148,661,662],{"class":150,"line":170},[148,663,664],{},"\u002F\u002F 在插件域中加载程序集\n",[148,666,667],{"class":150,"line":176},[148,668,669],{},"pluginDomain.Load(assemblyName);\n",[148,671,672],{"class":150,"line":182},[148,673,167],{"emptyLinePlaceholder":166},[148,675,676],{"class":150,"line":187},[148,677,678],{},"\u002F\u002F 卸载插件域\n",[148,680,681],{"class":150,"line":193},[148,682,683],{},"AppDomain.Unload(pluginDomain);\n",[78,685,687],{"id":686},"_53-内存管理","5.3 内存管理",[83,689,690,693,696],{},[21,691,692],{},"程序集缓存",[21,694,695],{},"垃圾回收",[21,697,698],{},"内存泄漏预防",[71,700],{},[14,702,704],{"id":703},"_6-依赖注入与扩展","6. 依赖注入与扩展",[78,706,708],{"id":707},"_61-服务容器集成","6.1 服务容器集成",[138,710,712],{"className":140,"code":711,"language":142,"meta":143,"style":143},"\u002F\u002F 使用Microsoft.Extensions.DependencyInjection\npublic void ConfigureServices(IServiceCollection services)\n{\n    \u002F\u002F 扫描程序集注册服务\n    var assemblies = Directory.GetFiles(pluginDirectory, \"*.dll\")\n        .Select(Assembly.LoadFrom);\n        \n    foreach (var assembly in assemblies)\n    {\n        services.AddServicesFromAssembly(assembly);\n    }\n}\n",[145,713,714,719,724,728,733,738,743,747,752,756,761,765],{"__ignoreMap":143},[148,715,716],{"class":150,"line":151},[148,717,718],{},"\u002F\u002F 使用Microsoft.Extensions.DependencyInjection\n",[148,720,721],{"class":150,"line":157},[148,722,723],{},"public void ConfigureServices(IServiceCollection services)\n",[148,725,726],{"class":150,"line":163},[148,727,368],{},[148,729,730],{"class":150,"line":170},[148,731,732],{},"    \u002F\u002F 扫描程序集注册服务\n",[148,734,735],{"class":150,"line":176},[148,736,737],{},"    var assemblies = Directory.GetFiles(pluginDirectory, \"*.dll\")\n",[148,739,740],{"class":150,"line":182},[148,741,742],{},"        .Select(Assembly.LoadFrom);\n",[148,744,745],{"class":150,"line":187},[148,746,393],{},[148,748,749],{"class":150,"line":193},[148,750,751],{},"    foreach (var assembly in assemblies)\n",[148,753,754],{"class":150,"line":401},[148,755,378],{},[148,757,758],{"class":150,"line":407},[148,759,760],{},"        services.AddServicesFromAssembly(assembly);\n",[148,762,763],{"class":150,"line":413},[148,764,481],{},[148,766,767],{"class":150,"line":419},[148,768,487],{},[78,770,772],{"id":771},"_62-扩展点设计","6.2 扩展点设计",[83,774,775,778,781],{},[21,776,777],{},"扩展接口定义",[21,779,780],{},"扩展发现机制",[21,782,783],{},"扩展注册",[78,785,787],{"id":786},"_63-热插拔支持","6.3 热插拔支持",[83,789,790,793,796],{},[21,791,792],{},"文件监控",[21,794,795],{},"动态重载",[21,797,798],{},"状态管理",[71,800],{},[14,802,804],{"id":803},"_7-实际应用案例","7. 实际应用案例",[78,806,808],{"id":807},"_71-主题系统","7.1 主题系统",[138,810,812],{"className":140,"code":811,"language":142,"meta":143,"style":143},"public interface ITheme\n{\n    string Name { get; }\n    ResourceDictionary GetResources();\n}\n\n\u002F\u002F 动态加载主题\npublic void LoadTheme(string themePath)\n{\n    var assembly = Assembly.LoadFrom(themePath);\n    var themeType = assembly.GetTypes()\n        .FirstOrDefault(t => typeof(ITheme).IsAssignableFrom(t));\n        \n    if (themeType != null)\n    {\n        var theme = (ITheme)Activator.CreateInstance(themeType);\n        Application.Current.Resources.MergedDictionaries.Add(theme.GetResources());\n    }\n}\n",[145,813,814,819,823,827,832,836,840,845,850,854,859,864,869,873,878,882,887,892,896],{"__ignoreMap":143},[148,815,816],{"class":150,"line":151},[148,817,818],{},"public interface ITheme\n",[148,820,821],{"class":150,"line":157},[148,822,368],{},[148,824,825],{"class":150,"line":163},[148,826,516],{},[148,828,829],{"class":150,"line":170},[148,830,831],{},"    ResourceDictionary GetResources();\n",[148,833,834],{"class":150,"line":176},[148,835,487],{},[148,837,838],{"class":150,"line":182},[148,839,167],{"emptyLinePlaceholder":166},[148,841,842],{"class":150,"line":187},[148,843,844],{},"\u002F\u002F 动态加载主题\n",[148,846,847],{"class":150,"line":193},[148,848,849],{},"public void LoadTheme(string themePath)\n",[148,851,852],{"class":150,"line":401},[148,853,368],{},[148,855,856],{"class":150,"line":407},[148,857,858],{},"    var assembly = Assembly.LoadFrom(themePath);\n",[148,860,861],{"class":150,"line":413},[148,862,863],{},"    var themeType = assembly.GetTypes()\n",[148,865,866],{"class":150,"line":419},[148,867,868],{},"        .FirstOrDefault(t => typeof(ITheme).IsAssignableFrom(t));\n",[148,870,871],{"class":150,"line":425},[148,872,393],{},[148,874,875],{"class":150,"line":431},[148,876,877],{},"    if (themeType != null)\n",[148,879,880],{"class":150,"line":437},[148,881,378],{},[148,883,884],{"class":150,"line":443},[148,885,886],{},"        var theme = (ITheme)Activator.CreateInstance(themeType);\n",[148,888,889],{"class":150,"line":449},[148,890,891],{},"        Application.Current.Resources.MergedDictionaries.Add(theme.GetResources());\n",[148,893,894],{"class":150,"line":455},[148,895,481],{},[148,897,898],{"class":150,"line":461},[148,899,487],{},[78,901,903],{"id":902},"_72-控件扩展","7.2 控件扩展",[83,905,906,909,912],{},[21,907,908],{},"自定义控件库",[21,910,911],{},"动态控件加载",[21,913,914],{},"样式扩展",[78,916,918],{"id":917},"_73-业务模块化","7.3 业务模块化",[83,920,921,924,927],{},[21,922,923],{},"功能模块分离",[21,925,926],{},"按需加载",[21,928,929],{},"模块间通信",[71,931],{},[14,933,935],{"id":934},"_8-最佳实践与注意事项","8. 最佳实践与注意事项",[78,937,939],{"id":938},"_81-安全性考虑","8.1 安全性考虑",[83,941,942,945,948],{},[21,943,944],{},"程序集签名验证",[21,946,947],{},"权限控制",[21,949,950],{},"沙箱隔离",[78,952,954],{"id":953},"_82-性能优化","8.2 性能优化",[83,956,957,960,962],{},[21,958,959],{},"延迟加载",[21,961,692],{},[21,963,964],{},"资源管理",[78,966,968],{"id":967},"_83-错误处理","8.3 错误处理",[138,970,972],{"className":140,"code":971,"language":142,"meta":143,"style":143},"try\n{\n    var assembly = Assembly.LoadFrom(dllPath);\n    \u002F\u002F 处理加载成功\n}\ncatch (BadImageFormatException)\n{\n    \u002F\u002F 处理无效程序集\n}\ncatch (FileLoadException)\n{\n    \u002F\u002F 处理加载失败\n}\ncatch (Exception ex)\n{\n    \u002F\u002F 处理其他异常\n}\n",[145,973,974,979,983,988,993,997,1002,1006,1011,1015,1020,1024,1029,1033,1038,1042,1047],{"__ignoreMap":143},[148,975,976],{"class":150,"line":151},[148,977,978],{},"try\n",[148,980,981],{"class":150,"line":157},[148,982,368],{},[148,984,985],{"class":150,"line":163},[148,986,987],{},"    var assembly = Assembly.LoadFrom(dllPath);\n",[148,989,990],{"class":150,"line":170},[148,991,992],{},"    \u002F\u002F 处理加载成功\n",[148,994,995],{"class":150,"line":176},[148,996,487],{},[148,998,999],{"class":150,"line":182},[148,1000,1001],{},"catch (BadImageFormatException)\n",[148,1003,1004],{"class":150,"line":187},[148,1005,368],{},[148,1007,1008],{"class":150,"line":193},[148,1009,1010],{},"    \u002F\u002F 处理无效程序集\n",[148,1012,1013],{"class":150,"line":401},[148,1014,487],{},[148,1016,1017],{"class":150,"line":407},[148,1018,1019],{},"catch (FileLoadException)\n",[148,1021,1022],{"class":150,"line":413},[148,1023,368],{},[148,1025,1026],{"class":150,"line":419},[148,1027,1028],{},"    \u002F\u002F 处理加载失败\n",[148,1030,1031],{"class":150,"line":425},[148,1032,487],{},[148,1034,1035],{"class":150,"line":431},[148,1036,1037],{},"catch (Exception ex)\n",[148,1039,1040],{"class":150,"line":437},[148,1041,368],{},[148,1043,1044],{"class":150,"line":443},[148,1045,1046],{},"    \u002F\u002F 处理其他异常\n",[148,1048,1049],{"class":150,"line":449},[148,1050,487],{},[78,1052,1054],{"id":1053},"_84-调试与诊断","8.4 调试与诊断",[83,1056,1057,1060,1063],{},[21,1058,1059],{},"程序集加载日志",[21,1061,1062],{},"性能监控",[21,1064,1065],{},"内存分析",[78,1067,1069],{"id":1068},"_85-部署策略","8.5 部署策略",[83,1071,1072,1075,1078],{},[21,1073,1074],{},"程序集版本管理",[21,1076,1077],{},"依赖关系处理",[21,1079,1080],{},"更新机制",[71,1082],{},[14,1084,1085],{"id":1085},"总结",[213,1087,1088],{},"WPF中的DLL扩展加载为应用程序提供了强大的模块化和可扩展性能力。通过合理的设计和实现，可以构建出灵活、可维护的应用程序架构。关键是要平衡灵活性、性能和安全性，选择合适的加载策略和架构模式。",[14,1090,1091],{"id":1091},"实操",[213,1093,1094],{},"​\t我们在wpf中需要建立一个wpf类库，然后在这个基础上引用原来的库，最后将其编译为dll就行，记得使用项目引用，可以防止再新建一个公用的类库。",[213,1096,1097],{},"首先我们需要一个加载dll的方法实现。",[138,1099,1101],{"className":140,"code":1100,"language":142,"meta":143,"style":143},"private void LoadExtentions()\n{\n    try\n    {\n        string pluginPath = Path.Combine(AppContext.BaseDirectory, \"Extensions\");\n        if (!Directory.Exists(pluginPath))\n        {\n            Console.WriteLine(\"Extensions folder not found.\");\n            return;\n        }\n        \n        var dllFiles = Directory.GetFiles(pluginPath, \"*.dll\");\n        if(!dllFiles.Any())\n        {\n            Console.WriteLine(\"No plugins found.\");\n            return;\n        }\n        \n        var extensionPages = new List\u003C(Type PageType, Type ViewModelType, string Title)>();\n        \n        foreach (var dllFile in dllFiles) {\n            var assembly = Assembly.LoadFrom(dllFile);\n            Console.WriteLine($\"Loaded plugin: {assembly.GetName().Name}\");\n\n            var viewModelTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(ExtentionViewModel))).ToList();\n            var pageTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Page))).ToList();\n            \n            foreach (var pageType in pageTypes)\n            {\n                var viewModelType = viewModelTypes.FirstOrDefault(vm => \n                    vm.Name == pageType.Name + \"ViewModel\");\n                \n                string title = GetPageTitle(viewModelType, pageType);\n                extensionPages.Add((pageType, viewModelType, title));\n                \n                Console.WriteLine($\"Found extension: {title} - {pageType.Name}\");\n            }\n        }\n        \n        ExtensionPages = extensionPages;\n        Console.WriteLine($\"Total extensions loaded: {ExtensionPages.Count}\");\n    }\n    catch (Exception ex) { \n        Console.WriteLine($\"Failed to load plugin: {ex.Message}\");\n    }\n}\n",[145,1102,1103,1108,1112,1117,1121,1126,1131,1135,1140,1145,1149,1153,1158,1163,1167,1172,1176,1180,1184,1189,1193,1198,1203,1208,1213,1219,1225,1231,1237,1242,1248,1254,1259,1265,1271,1276,1282,1287,1292,1297,1303,1309,1314,1320,1326,1331],{"__ignoreMap":143},[148,1104,1105],{"class":150,"line":151},[148,1106,1107],{},"private void LoadExtentions()\n",[148,1109,1110],{"class":150,"line":157},[148,1111,368],{},[148,1113,1114],{"class":150,"line":163},[148,1115,1116],{},"    try\n",[148,1118,1119],{"class":150,"line":170},[148,1120,378],{},[148,1122,1123],{"class":150,"line":176},[148,1124,1125],{},"        string pluginPath = Path.Combine(AppContext.BaseDirectory, \"Extensions\");\n",[148,1127,1128],{"class":150,"line":182},[148,1129,1130],{},"        if (!Directory.Exists(pluginPath))\n",[148,1132,1133],{"class":150,"line":187},[148,1134,404],{},[148,1136,1137],{"class":150,"line":193},[148,1138,1139],{},"            Console.WriteLine(\"Extensions folder not found.\");\n",[148,1141,1142],{"class":150,"line":401},[148,1143,1144],{},"            return;\n",[148,1146,1147],{"class":150,"line":407},[148,1148,464],{},[148,1150,1151],{"class":150,"line":413},[148,1152,393],{},[148,1154,1155],{"class":150,"line":419},[148,1156,1157],{},"        var dllFiles = Directory.GetFiles(pluginPath, \"*.dll\");\n",[148,1159,1160],{"class":150,"line":425},[148,1161,1162],{},"        if(!dllFiles.Any())\n",[148,1164,1165],{"class":150,"line":431},[148,1166,404],{},[148,1168,1169],{"class":150,"line":437},[148,1170,1171],{},"            Console.WriteLine(\"No plugins found.\");\n",[148,1173,1174],{"class":150,"line":443},[148,1175,1144],{},[148,1177,1178],{"class":150,"line":449},[148,1179,464],{},[148,1181,1182],{"class":150,"line":455},[148,1183,393],{},[148,1185,1186],{"class":150,"line":461},[148,1187,1188],{},"        var extensionPages = new List\u003C(Type PageType, Type ViewModelType, string Title)>();\n",[148,1190,1191],{"class":150,"line":467},[148,1192,393],{},[148,1194,1195],{"class":150,"line":472},[148,1196,1197],{},"        foreach (var dllFile in dllFiles) {\n",[148,1199,1200],{"class":150,"line":478},[148,1201,1202],{},"            var assembly = Assembly.LoadFrom(dllFile);\n",[148,1204,1205],{"class":150,"line":484},[148,1206,1207],{},"            Console.WriteLine($\"Loaded plugin: {assembly.GetName().Name}\");\n",[148,1209,1211],{"class":150,"line":1210},24,[148,1212,167],{"emptyLinePlaceholder":166},[148,1214,1216],{"class":150,"line":1215},25,[148,1217,1218],{},"            var viewModelTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(ExtentionViewModel))).ToList();\n",[148,1220,1222],{"class":150,"line":1221},26,[148,1223,1224],{},"            var pageTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Page))).ToList();\n",[148,1226,1228],{"class":150,"line":1227},27,[148,1229,1230],{},"            \n",[148,1232,1234],{"class":150,"line":1233},28,[148,1235,1236],{},"            foreach (var pageType in pageTypes)\n",[148,1238,1240],{"class":150,"line":1239},29,[148,1241,440],{},[148,1243,1245],{"class":150,"line":1244},30,[148,1246,1247],{},"                var viewModelType = viewModelTypes.FirstOrDefault(vm => \n",[148,1249,1251],{"class":150,"line":1250},31,[148,1252,1253],{},"                    vm.Name == pageType.Name + \"ViewModel\");\n",[148,1255,1257],{"class":150,"line":1256},32,[148,1258,428],{},[148,1260,1262],{"class":150,"line":1261},33,[148,1263,1264],{},"                string title = GetPageTitle(viewModelType, pageType);\n",[148,1266,1268],{"class":150,"line":1267},34,[148,1269,1270],{},"                extensionPages.Add((pageType, viewModelType, title));\n",[148,1272,1274],{"class":150,"line":1273},35,[148,1275,428],{},[148,1277,1279],{"class":150,"line":1278},36,[148,1280,1281],{},"                Console.WriteLine($\"Found extension: {title} - {pageType.Name}\");\n",[148,1283,1285],{"class":150,"line":1284},37,[148,1286,458],{},[148,1288,1290],{"class":150,"line":1289},38,[148,1291,464],{},[148,1293,1295],{"class":150,"line":1294},39,[148,1296,393],{},[148,1298,1300],{"class":150,"line":1299},40,[148,1301,1302],{},"        ExtensionPages = extensionPages;\n",[148,1304,1306],{"class":150,"line":1305},41,[148,1307,1308],{},"        Console.WriteLine($\"Total extensions loaded: {ExtensionPages.Count}\");\n",[148,1310,1312],{"class":150,"line":1311},42,[148,1313,481],{},[148,1315,1317],{"class":150,"line":1316},43,[148,1318,1319],{},"    catch (Exception ex) { \n",[148,1321,1323],{"class":150,"line":1322},44,[148,1324,1325],{},"        Console.WriteLine($\"Failed to load plugin: {ex.Message}\");\n",[148,1327,1329],{"class":150,"line":1328},45,[148,1330,481],{},[148,1332,1334],{"class":150,"line":1333},46,[148,1335,487],{},[213,1337,1338],{},"​\t然后我们使用静态属性类去存储扩展页面的信息：",[213,1340,1341],{},[217,1342,1343],{},"public static List\u003C(Type PageType, Type ViewModelType, string Title)> ExtensionPages { get; private set; } = new();",[213,1345,1346],{},"​\t这个方法是加载继承了ExtensionViewModel 和 Page 类 的类方法，我们需要从获得的viewmodel类中得到我们想要的Title Icon等信息。",[138,1348,1350],{"className":140,"code":1349,"language":142,"meta":143,"style":143},"private string GetPageTitle(Type viewModelType, Type pageType)\n{\n    if (viewModelType != null)\n    {\n        try\n        {\n            var instance = Activator.CreateInstance(viewModelType);\n            \n            \u002F\u002F 尝试 Title 属性\n            var titleProperty = viewModelType.GetProperty(\"Title\");\n            if (titleProperty != null)\n            {\n                var title = titleProperty.GetValue(instance) as string;\n                Console.WriteLine($\"Title property value: '{title}'\");\n                if (!string.IsNullOrEmpty(title)) return title;\n            }\n            else\n            {\n                Console.WriteLine(\"Title property not found\");\n            }\n            \n            \u002F\u002F 尝试 DisplayName 属性\n            var displayNameProperty = viewModelType.GetProperty(\"DisplayName\");\n            if (displayNameProperty != null)\n            {\n                var displayName = displayNameProperty.GetValue(instance) as string;\n                Console.WriteLine($\"DisplayName property value: '{displayName}'\");\n                if (!string.IsNullOrEmpty(displayName)) return displayName;\n            }\n            \n        }\n        catch (Exception ex)\n        {\n            Console.WriteLine($\"Error creating ViewModel instance: {ex.Message}\");\n        }\n    }\n    \n    \u002F\u002F 默认使用类名（去掉Page后缀）\n    string className = pageType.Name;\n    if (className.EndsWith(\"Page\"))\n    {\n        className = className.Substring(0, className.Length - 4);\n    }\n    \n    Console.WriteLine($\"Using default class name: '{className}'\");\n    return className;\n}\n",[145,1351,1352,1357,1361,1366,1370,1375,1379,1384,1388,1393,1398,1403,1407,1412,1417,1422,1426,1431,1435,1440,1444,1448,1453,1458,1463,1467,1472,1477,1482,1486,1490,1494,1499,1503,1508,1512,1516,1521,1526,1531,1536,1540,1545,1549,1553,1558,1563],{"__ignoreMap":143},[148,1353,1354],{"class":150,"line":151},[148,1355,1356],{},"private string GetPageTitle(Type viewModelType, Type pageType)\n",[148,1358,1359],{"class":150,"line":157},[148,1360,368],{},[148,1362,1363],{"class":150,"line":163},[148,1364,1365],{},"    if (viewModelType != null)\n",[148,1367,1368],{"class":150,"line":170},[148,1369,378],{},[148,1371,1372],{"class":150,"line":176},[148,1373,1374],{},"        try\n",[148,1376,1377],{"class":150,"line":182},[148,1378,404],{},[148,1380,1381],{"class":150,"line":187},[148,1382,1383],{},"            var instance = Activator.CreateInstance(viewModelType);\n",[148,1385,1386],{"class":150,"line":193},[148,1387,1230],{},[148,1389,1390],{"class":150,"line":401},[148,1391,1392],{},"            \u002F\u002F 尝试 Title 属性\n",[148,1394,1395],{"class":150,"line":407},[148,1396,1397],{},"            var titleProperty = viewModelType.GetProperty(\"Title\");\n",[148,1399,1400],{"class":150,"line":413},[148,1401,1402],{},"            if (titleProperty != null)\n",[148,1404,1405],{"class":150,"line":419},[148,1406,440],{},[148,1408,1409],{"class":150,"line":425},[148,1410,1411],{},"                var title = titleProperty.GetValue(instance) as string;\n",[148,1413,1414],{"class":150,"line":431},[148,1415,1416],{},"                Console.WriteLine($\"Title property value: '{title}'\");\n",[148,1418,1419],{"class":150,"line":437},[148,1420,1421],{},"                if (!string.IsNullOrEmpty(title)) return title;\n",[148,1423,1424],{"class":150,"line":443},[148,1425,458],{},[148,1427,1428],{"class":150,"line":449},[148,1429,1430],{},"            else\n",[148,1432,1433],{"class":150,"line":455},[148,1434,440],{},[148,1436,1437],{"class":150,"line":461},[148,1438,1439],{},"                Console.WriteLine(\"Title property not found\");\n",[148,1441,1442],{"class":150,"line":467},[148,1443,458],{},[148,1445,1446],{"class":150,"line":472},[148,1447,1230],{},[148,1449,1450],{"class":150,"line":478},[148,1451,1452],{},"            \u002F\u002F 尝试 DisplayName 属性\n",[148,1454,1455],{"class":150,"line":484},[148,1456,1457],{},"            var displayNameProperty = viewModelType.GetProperty(\"DisplayName\");\n",[148,1459,1460],{"class":150,"line":1210},[148,1461,1462],{},"            if (displayNameProperty != null)\n",[148,1464,1465],{"class":150,"line":1215},[148,1466,440],{},[148,1468,1469],{"class":150,"line":1221},[148,1470,1471],{},"                var displayName = displayNameProperty.GetValue(instance) as string;\n",[148,1473,1474],{"class":150,"line":1227},[148,1475,1476],{},"                Console.WriteLine($\"DisplayName property value: '{displayName}'\");\n",[148,1478,1479],{"class":150,"line":1233},[148,1480,1481],{},"                if (!string.IsNullOrEmpty(displayName)) return displayName;\n",[148,1483,1484],{"class":150,"line":1239},[148,1485,458],{},[148,1487,1488],{"class":150,"line":1244},[148,1489,1230],{},[148,1491,1492],{"class":150,"line":1250},[148,1493,464],{},[148,1495,1496],{"class":150,"line":1256},[148,1497,1498],{},"        catch (Exception ex)\n",[148,1500,1501],{"class":150,"line":1261},[148,1502,404],{},[148,1504,1505],{"class":150,"line":1267},[148,1506,1507],{},"            Console.WriteLine($\"Error creating ViewModel instance: {ex.Message}\");\n",[148,1509,1510],{"class":150,"line":1273},[148,1511,464],{},[148,1513,1514],{"class":150,"line":1278},[148,1515,481],{},[148,1517,1518],{"class":150,"line":1284},[148,1519,1520],{},"    \n",[148,1522,1523],{"class":150,"line":1289},[148,1524,1525],{},"    \u002F\u002F 默认使用类名（去掉Page后缀）\n",[148,1527,1528],{"class":150,"line":1294},[148,1529,1530],{},"    string className = pageType.Name;\n",[148,1532,1533],{"class":150,"line":1299},[148,1534,1535],{},"    if (className.EndsWith(\"Page\"))\n",[148,1537,1538],{"class":150,"line":1305},[148,1539,378],{},[148,1541,1542],{"class":150,"line":1311},[148,1543,1544],{},"        className = className.Substring(0, className.Length - 4);\n",[148,1546,1547],{"class":150,"line":1316},[148,1548,481],{},[148,1550,1551],{"class":150,"line":1322},[148,1552,1520],{},[148,1554,1555],{"class":150,"line":1328},[148,1556,1557],{},"    Console.WriteLine($\"Using default class name: '{className}'\");\n",[148,1559,1560],{"class":150,"line":1333},[148,1561,1562],{},"    return className;\n",[148,1564,1566],{"class":150,"line":1565},47,[148,1567,487],{},[213,1569,1570],{},"​\t完成之后我们就可以去写依赖注入的服务注册扩展实现的方法",[138,1572,1574],{"className":140,"code":1573,"language":142,"meta":143,"style":143},"    private void RegisterExtensionPages(IServiceCollection services)\n    {\n        foreach (var (pageType, viewModelType, title) in ExtensionPages)\n        {\n            services.AddSingleton(pageType);\n            if (viewModelType != null)\n            {\n                services.AddSingleton(viewModelType);\n            }\n            Console.WriteLine($\"Registered extension: {title}\");\n        }\n    }\n",[145,1575,1576,1581,1585,1590,1594,1599,1604,1608,1613,1617,1622,1626],{"__ignoreMap":143},[148,1577,1578],{"class":150,"line":151},[148,1579,1580],{},"    private void RegisterExtensionPages(IServiceCollection services)\n",[148,1582,1583],{"class":150,"line":157},[148,1584,378],{},[148,1586,1587],{"class":150,"line":163},[148,1588,1589],{},"        foreach (var (pageType, viewModelType, title) in ExtensionPages)\n",[148,1591,1592],{"class":150,"line":170},[148,1593,404],{},[148,1595,1596],{"class":150,"line":176},[148,1597,1598],{},"            services.AddSingleton(pageType);\n",[148,1600,1601],{"class":150,"line":182},[148,1602,1603],{},"            if (viewModelType != null)\n",[148,1605,1606],{"class":150,"line":187},[148,1607,440],{},[148,1609,1610],{"class":150,"line":193},[148,1611,1612],{},"                services.AddSingleton(viewModelType);\n",[148,1614,1615],{"class":150,"line":401},[148,1616,458],{},[148,1618,1619],{"class":150,"line":407},[148,1620,1621],{},"            Console.WriteLine($\"Registered extension: {title}\");\n",[148,1623,1624],{"class":150,"line":413},[148,1625,464],{},[148,1627,1628],{"class":150,"line":419},[148,1629,481],{},[213,1631,1632],{},"​\t最后在导航栏一侧去注册就ok了，当然也可以通过反射程序集的方式加载导航栏，看自己的项目需求，下面是获取图标和添加导航的方法实现。",[138,1634,1636],{"className":140,"code":1635,"language":142,"meta":143,"style":143},"    private void InitializeMenuItems()\n    {\n        \u002F\u002F 添加默认菜单项\n        _menuItems.Add(new NavigationViewItem(\"Home\", SymbolRegular.Home24, typeof(DashboardPage)));\n        _menuItems.Add(new NavigationViewItem(\"Color采集\", SymbolRegular.Color24, typeof(ColorCollecterPage)));\n\n        \u002F\u002F 添加扩展页面的菜单项\n        foreach (var (pageType, viewModelType, title) in App.ExtensionPages)\n        {\n            \u002F\u002F 尝试从ViewModel获取图标\n            var icon = GetIconFromViewModel(viewModelType);\n            \n            var menuItem = new NavigationViewItem(title, icon, pageType)\n            {\n                ToolTip = $\"打开{title}扩展\"\n            };\n            _menuItems.Add(menuItem);\n        }\n    }\n\n\u002F\u002F 获取图标\n    private SymbolRegular GetIconFromViewModel(Type viewModelType)\n    {\n        if (viewModelType != null)\n        {\n            try\n            {\n                \u002F\u002F 尝试从 Icon 属性获取图标\n                var iconProperty = viewModelType.GetProperty(\"Icon\");\n                if (iconProperty != null)\n                {\n                    var instance = Activator.CreateInstance(viewModelType);\n                    var icon = iconProperty.GetValue(instance);\n                    if (icon is SymbolRegular symbolIcon)\n                    {\n                        return symbolIcon;\n                    }\n                }\n            }\n            catch\n            {\n                \u002F\u002F 如果无法获取图标，使用默认图标\n            }\n        }\n        \u002F\u002F 默认图标\n        return SymbolRegular.Home24;\n    }\n",[145,1637,1638,1643,1647,1652,1657,1662,1666,1671,1676,1680,1685,1690,1694,1699,1703,1708,1713,1718,1722,1726,1730,1735,1740,1744,1749,1753,1758,1762,1767,1772,1777,1782,1787,1792,1797,1802,1807,1812,1817,1821,1826,1830,1835,1839,1843,1848,1853],{"__ignoreMap":143},[148,1639,1640],{"class":150,"line":151},[148,1641,1642],{},"    private void InitializeMenuItems()\n",[148,1644,1645],{"class":150,"line":157},[148,1646,378],{},[148,1648,1649],{"class":150,"line":163},[148,1650,1651],{},"        \u002F\u002F 添加默认菜单项\n",[148,1653,1654],{"class":150,"line":170},[148,1655,1656],{},"        _menuItems.Add(new NavigationViewItem(\"Home\", SymbolRegular.Home24, typeof(DashboardPage)));\n",[148,1658,1659],{"class":150,"line":176},[148,1660,1661],{},"        _menuItems.Add(new NavigationViewItem(\"Color采集\", SymbolRegular.Color24, typeof(ColorCollecterPage)));\n",[148,1663,1664],{"class":150,"line":182},[148,1665,167],{"emptyLinePlaceholder":166},[148,1667,1668],{"class":150,"line":187},[148,1669,1670],{},"        \u002F\u002F 添加扩展页面的菜单项\n",[148,1672,1673],{"class":150,"line":193},[148,1674,1675],{},"        foreach (var (pageType, viewModelType, title) in App.ExtensionPages)\n",[148,1677,1678],{"class":150,"line":401},[148,1679,404],{},[148,1681,1682],{"class":150,"line":407},[148,1683,1684],{},"            \u002F\u002F 尝试从ViewModel获取图标\n",[148,1686,1687],{"class":150,"line":413},[148,1688,1689],{},"            var icon = GetIconFromViewModel(viewModelType);\n",[148,1691,1692],{"class":150,"line":419},[148,1693,1230],{},[148,1695,1696],{"class":150,"line":425},[148,1697,1698],{},"            var menuItem = new NavigationViewItem(title, icon, pageType)\n",[148,1700,1701],{"class":150,"line":431},[148,1702,440],{},[148,1704,1705],{"class":150,"line":437},[148,1706,1707],{},"                ToolTip = $\"打开{title}扩展\"\n",[148,1709,1710],{"class":150,"line":443},[148,1711,1712],{},"            };\n",[148,1714,1715],{"class":150,"line":449},[148,1716,1717],{},"            _menuItems.Add(menuItem);\n",[148,1719,1720],{"class":150,"line":455},[148,1721,464],{},[148,1723,1724],{"class":150,"line":461},[148,1725,481],{},[148,1727,1728],{"class":150,"line":467},[148,1729,167],{"emptyLinePlaceholder":166},[148,1731,1732],{"class":150,"line":472},[148,1733,1734],{},"\u002F\u002F 获取图标\n",[148,1736,1737],{"class":150,"line":478},[148,1738,1739],{},"    private SymbolRegular GetIconFromViewModel(Type viewModelType)\n",[148,1741,1742],{"class":150,"line":484},[148,1743,378],{},[148,1745,1746],{"class":150,"line":1210},[148,1747,1748],{},"        if (viewModelType != null)\n",[148,1750,1751],{"class":150,"line":1215},[148,1752,404],{},[148,1754,1755],{"class":150,"line":1221},[148,1756,1757],{},"            try\n",[148,1759,1760],{"class":150,"line":1227},[148,1761,440],{},[148,1763,1764],{"class":150,"line":1233},[148,1765,1766],{},"                \u002F\u002F 尝试从 Icon 属性获取图标\n",[148,1768,1769],{"class":150,"line":1239},[148,1770,1771],{},"                var iconProperty = viewModelType.GetProperty(\"Icon\");\n",[148,1773,1774],{"class":150,"line":1244},[148,1775,1776],{},"                if (iconProperty != null)\n",[148,1778,1779],{"class":150,"line":1250},[148,1780,1781],{},"                {\n",[148,1783,1784],{"class":150,"line":1256},[148,1785,1786],{},"                    var instance = Activator.CreateInstance(viewModelType);\n",[148,1788,1789],{"class":150,"line":1261},[148,1790,1791],{},"                    var icon = iconProperty.GetValue(instance);\n",[148,1793,1794],{"class":150,"line":1267},[148,1795,1796],{},"                    if (icon is SymbolRegular symbolIcon)\n",[148,1798,1799],{"class":150,"line":1273},[148,1800,1801],{},"                    {\n",[148,1803,1804],{"class":150,"line":1278},[148,1805,1806],{},"                        return symbolIcon;\n",[148,1808,1809],{"class":150,"line":1284},[148,1810,1811],{},"                    }\n",[148,1813,1814],{"class":150,"line":1289},[148,1815,1816],{},"                }\n",[148,1818,1819],{"class":150,"line":1294},[148,1820,458],{},[148,1822,1823],{"class":150,"line":1299},[148,1824,1825],{},"            catch\n",[148,1827,1828],{"class":150,"line":1305},[148,1829,440],{},[148,1831,1832],{"class":150,"line":1311},[148,1833,1834],{},"                \u002F\u002F 如果无法获取图标，使用默认图标\n",[148,1836,1837],{"class":150,"line":1316},[148,1838,458],{},[148,1840,1841],{"class":150,"line":1322},[148,1842,464],{},[148,1844,1845],{"class":150,"line":1328},[148,1846,1847],{},"        \u002F\u002F 默认图标\n",[148,1849,1850],{"class":150,"line":1333},[148,1851,1852],{},"        return SymbolRegular.Home24;\n",[148,1854,1855],{"class":150,"line":1565},[148,1856,481],{},[213,1858,1859,1860,256],{},"​\t但是这里要注意一件事情，那就是这种加载方式下，xaml的加载不同于我们之前使用的 在 this.DataContext = this;方法 ，可以在xaml上用ViewModel.进行绑定，默认情况下，如果在插件实现的库中这样写有很大概率是找不到你的viewModel的，会出现绑定失败的，因此一般情况下，",[217,1861,1862],{},"推荐直接使用ViewModel进行 业务逻辑和数据的绑定",[1864,1865,1866],"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":143,"searchDepth":157,"depth":157,"links":1868},[1869,1870,1875,1880,1886,1892,1897,1902,1907,1914,1915],{"id":16,"depth":157,"text":16},{"id":75,"depth":157,"text":76,"children":1871},[1872,1873,1874],{"id":80,"depth":163,"text":81},{"id":96,"depth":163,"text":97},{"id":111,"depth":163,"text":112},{"id":131,"depth":157,"text":132,"children":1876},[1877,1878,1879],{"id":135,"depth":163,"text":136},{"id":199,"depth":163,"text":200},{"id":274,"depth":163,"text":275},{"id":289,"depth":157,"text":290,"children":1881},[1882,1883,1884,1885],{"id":293,"depth":163,"text":294},{"id":308,"depth":163,"text":309},{"id":337,"depth":163,"text":338},{"id":352,"depth":163,"text":353},{"id":492,"depth":157,"text":493,"children":1887},[1888,1889,1890,1891],{"id":496,"depth":163,"text":497},{"id":543,"depth":163,"text":544},{"id":561,"depth":163,"text":562},{"id":576,"depth":163,"text":577},{"id":620,"depth":157,"text":621,"children":1893},[1894,1895,1896],{"id":624,"depth":163,"text":625},{"id":639,"depth":163,"text":640},{"id":686,"depth":163,"text":687},{"id":703,"depth":157,"text":704,"children":1898},[1899,1900,1901],{"id":707,"depth":163,"text":708},{"id":771,"depth":163,"text":772},{"id":786,"depth":163,"text":787},{"id":803,"depth":157,"text":804,"children":1903},[1904,1905,1906],{"id":807,"depth":163,"text":808},{"id":902,"depth":163,"text":903},{"id":917,"depth":163,"text":918},{"id":934,"depth":157,"text":935,"children":1908},[1909,1910,1911,1912,1913],{"id":938,"depth":163,"text":939},{"id":953,"depth":163,"text":954},{"id":967,"depth":163,"text":968},{"id":1053,"depth":163,"text":1054},{"id":1068,"depth":163,"text":1069},{"id":1085,"depth":157,"text":1085},{"id":1091,"depth":157,"text":1091},"md",{},"\u002Fcsharp\u002Fwpf\u002Fwpf和dll扩展加载",{"title":5,"description":143},"csharp\u002FWPF\u002Fwpf和dll扩展加载","AL_3tS9yd1JR7TK6r21UENZc_HAq0e2hWFS6-mxmtJ0",1791042465754]