来自带有构造函数参数的 lambda 的 RelayCommand

2023-12-11

如果在 XAML 文件中,我将一个 Button 绑定到以下类中的“Command”,则单击该 Button 不会导致执行 DoIt:

class Thing()
{
  public Thing(Foo p1)
  {
    Command = new RelayCommand(() => DoIt(p1));
  }

  private DoIt(Foo p)
  {
    p.DoSomething();
  }

  public ICommand Command { get; private set; }
}

但是,如果我从 p1 初始化一个字段并将该字段作为参数传递给 lambda 内的方法调用,它就会起作用:

class Thing()
{
  private Foo field;
  public Thing(Foo p1)
  {
    field = p1;
    Command = new RelayCommand(() => DoIt(field));
  }

  private DoIt(Foo p)
  {
    p.DoSomething();
  }

  public ICommand Command { get; private set; }
}

为什么前者失败,而后者却按预期工作?

可能相关:闭包在幕后是如何工作的? (C#)

编辑:为了澄清,以下内容也对我有用。但是,我仍然想知道为什么第二个示例达到了我的预期,但第一个示例却没有。

class Thing()
{
  private Foo field;
  public Thing(Foo p1)
  {
    field = p1;
    Command = new RelayCommand(DoIt);
    //Command = new RelayCommand(() => DoIt()); Equivalent?
  }

  private DoIt()
  {
    field.DoSomething();
  }

  public ICommand Command { get; private set; }
}

这是一个老问题,但我最近偶然发现了这个话题,值得回答。

这种奇怪行为的原因源于 MVVM Light 的实现RelayCommand。 execute 和 canexecute 处理程序存储为WeakAction _execute and WeakFunc<bool> _canExecute在继电器命令中。这WeakAction是当命令由于某种原因仍被 UI 引用时允许 GC 清理视图模型的尝试。

跳过一些细节,底线是:分配一个视图模型方法作为处理程序效果很好,因为WeakAction只要视图模型保持活动状态,它就会保持活动状态。对于动态创建的Action,情况有所不同。如果对该操作的唯一引用位于RelayCommand,只有弱引用存在,GC可以随时收集动作,把整个RelayCommand变成一块死砖。

好的,是时候了解细节了。实施WeakAction不是盲目地存储对操作的弱引用 - 这会导致许多引用消失。相反,弱的组合Delegate.Target参考和Delegate.MethodInfo被储存了。对于静态方法,该方法将通过强引用来存储。

现在,这导致了 lambda 的三类:

  1. 静态方法:() => I_dont_access_anything_nonstatic()将被存储为强参考
  2. 成员变量的闭包:() => DoIt(field)闭包方法将在 viewmodel 类中创建,操作目标是 viewmodel,并且只要 viewmodel 保持活动状态,该方法就会保持活动状态。
  3. 局部变量的闭包:() => DoIt(p1)闭包将创建一个单独的类实例来存储捕获的变量。这个单独的实例将成为操作目标,并且不会有任何对它的强引用 - GC 在某个时刻进行清理

重要的:据我所知,罗斯林的这种行为可能会改变:Roslyn 中的委托缓存行为发生变化因此,今天案例 (2) 的工作代码有可能变成 Roslyn 的非工作代码。然而,我没有测试这个假设,结果可能完全不同。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

来自带有构造函数参数的 lambda 的 RelayCommand 的相关文章

随机推荐

  • 如何向 System.Type 添加元数据?

    我一直在研究一种语言 但就 NET 集成而言 到目前为止我只设法让原始类型发挥作用 昨晚我有了一个好主意 而不是试图弄清楚到底是什么System Type对于元组 模块和函数应该在类型检查期间 我可以做的是获取System Type of
  • 如何在shell脚本中向变量追加值

    我从属性中获取变量值 并且可以在 sh 文件中访问 但我无法向该变量附加另一个值 请建议 echo Build ID from properties BUILD ID Build ID from properties abcd v6 c1
  • 需要使图像从底到角:React Native

    I want to make image rounded from bottom of it Here is what I wanted to make 我尝试过设置边界半径 但它将适用于整个图像而不是底部 这是我的代码
  • 在 R 中重塑而不进行聚合(例如 MTurk 响应字符串)

    通常 我会为此使用一个非常基本的从长到宽的重塑 但它似乎正在删除我的聚合变量 设置是我在 Mechanical Turk 上有一项工作 我一式三份执行 我希望 MTurk1 Mturk2 MTurk3 的答案成为数据框中它们自己的变量 但由
  • iOS 6 中仅横向使用 CCLayer 的 Cocos2d 中的游戏中心身份验证

    我遇到的问题似乎是一个相当常见的问题 但我的解决方案的搜索和实现尚未成功 我构建了一个 Cocos2d 游戏 该游戏仅供横向使用 但需要访问 Gamecenter Gamecenter 正在运行 启用了纵向模式 但它也允许游戏切换到纵向模式
  • 如何在 Inno Setup 中延迟而不冻结

    您好 我想知道如何在 Inno Setup Pascal Script 中将工作 或命令 延迟指定时间 内置的Sleep const Milliseconds LongInt 睡觉时冻结所有工作 我实现的以下功能也使WizardForm无响
  • 非静态类如何调用另一个非静态类的方法?

    我有两个非静态类 我需要访问一个类上的方法以返回一个对象进行处理 但由于这两个类都是非静态的 我不能只以静态方式调用该方法 我也不能以非静态方式调用该方法 因为程序不知道对象的标识符 在任何事情之前 如果可能的话 我希望这两个对象都保持非静
  • 具有多个并发读取器且无写入器的 Dictionary 的线程安全性

    如果我初始化一个通用字典一次 并且不允许进一步添加 更新 删除 那么让多个线程在没有锁定的情况下从中读取是否安全 假设字典在读取器启动之前已初始化 非通用哈希表的帮助中有一条注释说它对于多个读者来说是安全的 但我没有看到通用字典的类似内容
  • 反应状态行为

    所以 最近我开始了一个新项目 我只使用功能组件 不确定这是否是此问题的相关声明 我已经初始化了一个这样的状态变量 const selectedFields setSelectedFields useState 在下面的函数中 我更新状态 l
  • 使用 awk 保持文件 1 中的行与文件 2 中的值匹配

    主文件的内容 cat Sort File2 csv SR 2017 09 01 00 19 13 05 30 1A3LA7015L5O 5042449534546015801549 SR 2017 09 01 00 19 13 05 30
  • 使用data.table在每组数据之前插入一行

    这也许是个愚蠢的问题 但我想在每组数据之前插入一个角色 我在网上能找到的只是如何在每个组后插入一行 此外 插入的行将有一个代表每个 ID 的序列号 例如 我有一个像这样的数据表 df ID TIME VAR VALUE 101 07 02
  • 如何以一致的方式从左到右、从上到下对轮廓进行排序

    我正在研究一个从图像中提取矩形框并按顺序对这些矩形框进行排序的问题 我尝试过的代码是 import cv2 import matplotlib pyplot as plt Load image grayscale adaptive thre
  • 在 Angular 2 组件模板中嵌入小部件

    我的一个组件模板需要有一个小部件https www tradingview com widget 它们提供了我们可以嵌入的脚本标签 但由于 Angular 2 从组件模板中删除了脚本标签 因此嵌入这些类型的小部件应该是最好的 我相信你会做这
  • UWP 应用安装程序自动更新无法正常工作

    我正在尝试从远程源自动更新我的 UWP 应用程序 为此我关注了这两个博客处理 sideloaded uwp and desktop bridge apps 的自动更新 创建应用安装程序文件 vsMSDN 的 我在版本 1803 操作系统内部
  • 可可得到一周的第一天

    如何获取约会一周的第一天 这似乎更容易 因为 当一周从星期日开始时 我需要取回星期日日期 如果从星期一开始 我需要获取星期一的日期 输入日期是一周内的任何日期 我尝试了几种方法 但边缘情况使其变得困难 我做了一个函数 但它不能 100 工作
  • Android 实时 Google 地图位置跟踪

    我正在开发一款 Android 应用程序 玩家可以根据自己的位置在手机上实时战斗 在 Google 地图上 您可以通过一个小蓝点看到您所在的位置 面向的方向以及正在移动的位置 我的问题是 如何将类似的东西集成到我的应用程序中 以便当玩家移动
  • Python:如何使用 Python 访问 mp3 文件的元数据? [复制]

    这个问题在这里已经有答案了 假设我想看看艺术家的名字 或者添加BPM信息 我可以使用哪些 Python 工具来完成此任务 有一个模块叫Python ID3正是这样做的 如果您使用的是 Debian Ubuntu 机器 则其软件包名称为pyt
  • 如何在Spring Data中进行Mongo聚合查询?

    这是我第一次在 Java 中使用 Mongo 这个聚合查询遇到了一些问题 我可以在 Mongo for Spring 中执行一些简单的查询 Query我的存储库接口中的注释扩展了MongoRepository
  • Python:在模块和类之间共享全局变量

    我知道在 Python 中可以跨模块共享全局变量 然而 我想知道这在多大程度上是可能的以及为什么 例如 全局mod py x None mid access mod py from global mod import class delta
  • 来自带有构造函数参数的 lambda 的 RelayCommand

    如果在 XAML 文件中 我将一个 Button 绑定到以下类中的 Command 则单击该 Button 不会导致执行 DoIt class Thing public Thing Foo p1 Command new RelayComma