当前位置: 首页 > news >正文

How do I duplicate a resource reference in code behind in WPF?如何在WPF后台代码中中复制引用的资源?...

原文 https://stackoverflow.com/questions/28240528/how-do-i-duplicate-a-resource-reference-in-code-behind-in-wpf

如何在WPF后台代码中中复制引用的资源?

In my application, I have a color resources. I have one element that uses that color as a dynamic resource in xaml.

  <Window x:Class="ResourcePlay.MainWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Title="MainWindow" Height="350" Width="425">
     <Window.Resources>
        <Color x:Key="MyColor">Red</Color>
     </Window.Resources>
     <Grid>
        <Rectangle VerticalAlignment="Top" Width="80" Height="80" Margin="10">
           <Rectangle.Fill>
              <SolidColorBrush x:Name="TopBrush" Color="{DynamicResource MyColor}"/>
           </Rectangle.Fill>
        </Rectangle>
        <Rectangle VerticalAlignment="Bottom" Width="80" Height="80" Margin="10">
           <Rectangle.Fill>
              <SolidColorBrush x:Name="BottomBrush"/>
           </Rectangle.Fill>
        </Rectangle>
     </Grid>
  </Window>

In the code, I want to duplicate this resource reference.

  using System.Windows;
  using System.Windows.Media;

  namespace ResourcePlay {
     public partial class MainWindow : Window {
        public MainWindow() {
           InitializeComponent();

           // I want to copy the resource reference, not the color.
           BottomBrush.Color = TopBrush.Color;

           // I'd really rather do something like this.
           var reference = TopBrush.GetResourceReference(SolidColorBrush.ColorProperty);
           BottomBrush.SetResourceReference(reference);

           // I want this to change the colors of both elements
           Resources["MyColor"] = Colors.Green;
        }
     }
  }

However, SetResourceReference only works for FrameworkElements or FrameworkContentElements. SolidColorBrush is just a Freezable. Also, I have no idea how to get a resource reference in code behind.

Is there a way to do this in WPF so that both of the colors change at the same time? In my real application, the problem isn't quite so simple, so I can't just add a second DynamicResource in xaml.
Il Vic suggested using reflection. Expanding on that, I was able to build some extension methods for DependencyObject that do what I want. I don't really like using reflection in code, and if someone else knows a better way to implement this, I'd love to see it. At least this will be helpful whenever I'm trying to debug DynamicResources from code behind.

  public static class DependencyObjectExtensions
  {
     public static object GetDynamicResourceKey(this DependencyObject obj, DependencyProperty prop)
     {
        // get the value entry from the depencency object for the specified dependency property
        var dependencyObject = typeof(DependencyObject);
        var dependencyObject_LookupEntry = dependencyObject.GetMethod("LookupEntry", BindingFlags.NonPublic | BindingFlags.Instance);
        var entryIndex = dependencyObject_LookupEntry.Invoke(obj, new object[] { prop.GlobalIndex });
        var effectiveValueEntry_GetValueEntry = dependencyObject.GetMethod("GetValueEntry", BindingFlags.NonPublic | BindingFlags.Instance);
        var valueEntry = effectiveValueEntry_GetValueEntry.Invoke(obj, new object[] { entryIndex, prop, null, 0x10 });

        // look inside the value entry to find the ModifiedValue object
        var effectiveValueEntry = valueEntry.GetType();
        var effectiveValueEntry_Value = effectiveValueEntry.GetProperty("Value", BindingFlags.Instance | BindingFlags.NonPublic);
        var effectiveValueEntry_Value_Getter = effectiveValueEntry_Value.GetGetMethod(nonPublic: true);
        var rawEntry = effectiveValueEntry_Value_Getter.Invoke(valueEntry, new object[0]);

        // look inside the ModifiedValue object to find the ResourceReference
        var modifiedValue = rawEntry.GetType();
        var modifiedValue_BaseValue = modifiedValue.GetProperty("BaseValue", BindingFlags.Instance | BindingFlags.NonPublic);
        var modifiedValue_BaseValue_Getter = modifiedValue_BaseValue.GetGetMethod(nonPublic: true);
        var resourceReferenceValue = modifiedValue_BaseValue_Getter.Invoke(rawEntry, new object[0]);

        // check the ResourceReference for the original ResourceKey
        var resourceReference = resourceReferenceValue.GetType();
        var resourceReference_resourceKey = resourceReference.GetField("_resourceKey", BindingFlags.NonPublic | BindingFlags.Instance);
        var resourceKey = resourceReference_resourceKey.GetValue(resourceReferenceValue);

        return resourceKey;
     }

     public static void SetDynamicResourceKey(this DependencyObject obj, DependencyProperty prop, object resourceKey)
     {
        var dynamicResource = new DynamicResourceExtension(resourceKey);
        var resourceReferenceExpression = dynamicResource.ProvideValue(null);
        obj.SetValue(prop, resourceReferenceExpression);
     }
  }

The second method uses DynamicResourceExtension to avoid some nastiness with Activator, but the first method feels incredibly brittle.

I can use these methods in my original example as follows:

  public MainWindow() {
     InitializeComponent();

     var key = TopBrush.GetDynamicResourceKey(SolidColorBrush.ColorProperty);
     BottomBrush.SetDynamicResourceKey(SolidColorBrush.ColorProperty, key);

     Resources["MyColor"] = Colors.Green;
  }

This will work for any DependencyProperty, provided it is set to a DynamicResource when we try to get the resource key. A little more finesse would be needed for production code.

 

相关文章:

  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • Commvault助力企业抵御勒索软件的蔓延
  • Mastering the game of Go with deep neural networks and tree search
  • 每周分享之JS数组的使用
  • python 内置模块
  • CSS 样式小结
  • TypeError: Cannot read property 'url' of undefined
  • centos 7 安装官方LAMP(Apache+PHP5+MySQL)
  • 6.Flask-WTForms
  • phpstrom+upupw 开启 Xdebug 调试
  • Python爬虫常用库的安装
  • 非 root 用户全局安装和配置 NodeJS
  • MYSQL性能优化的最佳20+条经验
  • 6.kotlin安卓实践课程-用kotlin写第一个activity对应P层
  • MHA源码分析——环境部署
  • $translatePartialLoader加载失败及解决方式
  • - C#编程大幅提高OUTLOOK的邮件搜索能力!
  • hadoop集群管理系统搭建规划说明
  • Laravel 实践之路: 数据库迁移与数据填充
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • ng6--错误信息小结(持续更新)
  • SpiderData 2019年2月23日 DApp数据排行榜
  • WePY 在小程序性能调优上做出的探究
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 机器学习中为什么要做归一化normalization
  • 批量截取pdf文件
  • 前端性能优化——回流与重绘
  • 深入浅出Node.js
  • 算法系列——算法入门之递归分而治之思想的实现
  • 怎么把视频里的音乐提取出来
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • 组复制官方翻译九、Group Replication Technical Details
  • ​flutter 代码混淆
  • ​iOS实时查看App运行日志
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • #define 用法
  • #stm32整理(一)flash读写
  • (c语言)strcpy函数用法
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (done) 两个矩阵 “相似” 是什么意思?
  • (function(){})()的分步解析
  • (二)学习JVM —— 垃圾回收机制
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (论文阅读40-45)图像描述1
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)Java算法:二分查找
  • (转)shell调试方法
  • (转)关于pipe()的详细解析
  • (轉)JSON.stringify 语法实例讲解
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • .cfg\.dat\.mak(持续补充)
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别