MVVM中的流畅表达式树绑定

本文探讨了一种使用表达式树实现的 Fluent 属性绑定技术,该技术在 MVVM 模式下用于观察对象属性变化。通过 `WhenChanged` 扩展方法,可以监听对象及嵌套属性的变更,自动处理订阅和取消订阅。测试用例展示了正确通知属性变更以及在对象替换时的处理方式。此外,文章还解释了如何在对象改变时重新订阅新属性并释放旧资源,以及如何通过 `Dispose` 方法彻底取消订阅。
摘要由CSDN通过智能技术生成

目录

项目URL和NuGet

代码

它是如何工作的?

所以现在的重点是EarlySourceBindingExpression是做什么的?

现在我们有了属性名称?

如果h.MainRoom是新的怎么办?

如果我需要完全取消订阅所有人怎么办?


项目URLNuGet

代码

让我们从结果开始。这些测试通过:

[Fact]
public void ShouldNotifyCorrectlyIfNestedPropertyChange()
{
    var house = new House();
    int counter = 0;
    house
        .WhenChanged(h => h.MainRoom.Table)
        .WhenChanged(h => h.Name)
        .With<PropertyChangeObserver>()
        .Do(() => counter++);

    house.MainRoom = new();
    house.MainRoom.Table = new();
    house.Name = "NewName";
    counter.Should().Be(3);
}

[Fact]
public void ShouldNotNotifyIfPropertyChangesOnOldReference()
{
    var house = new House
    {
        MainRoom = new()
        {
            Table = new()
        }
    };

    var counter = 0;
    house
        .WhenChanged(h => h.MainRoom.Table)
        .With<PropertyChangeObserver>()
        .Do(() => counter++);

    var oldRoom = house.MainRoom;
    house.MainRoom = new();
    oldRoom.Table = new();
    counter.Should().Be(1);
}

它是如何工作的?

让我们从头开始。WhenChanged是这样声明的:

public static IExpressionChangedBuilder<TSource> WhenChanged<TSource, TValue>
(this TSource @this, Expression<Func<TSource, TValue>> expression)
{
    IExpressionChangedBuilder<TSource> ret = 
               new EarlySourceBindingExpression<TSource>(@this);
    return ret.WhenChanged(expression);
}

所以现在的重点是EarlySourceBindingExpression是做什么的?

您可以看到,此类需要为构建(@this)一个参数。这将是从中开始搜索要绑定到的属性的对象。

扩展方法的第二个参数是表达式。

你可以把它看作是lambdah => h.MainRoom.Table,不被视为一个函数,而是作为组成lambda的所有部分的集合(树)。所以把它想成{h, h.MainRoom, h.MainRoom.Table}。表达式的每个部分(即 {h, h.MainRoom, h.MainRoom.Table}中的每个元素)都是一个对象,其中包含完全分类自身所需的所有元数据。因此,如果我们放置一个断点,探索表达式,我们可以看到:

  • hParameterExpression实例
  • h.MainRoomMemberExpression(Member = Property)实例
  • h.MainRoom.Table就是一个MemberExpression实例。

我们需要了解的是,MemberExpression类有一个叫做Member的字段。后者包含有关它所代表的成员的所有信息(最右边的一个),在这些之间,还有Name。在我们的例子中,因此我们可以分别从h.MainRoomh.MainRoom.Table获得stringMainRoomTable

现在我们有了属性名称?

现在我们有了stringMainRoomTable,我们只需要分别订阅hh.MainRoomNotifyPropertyChanged事件,并监听名为MainRoomTable的属性的变化。如果是这种情况,我们只需调用回调。

如果h.MainRoom是新的怎么办?

如果h.MainRoom更改,这意味着我们必须取消订阅所有旧的嵌套属性(旧的h.MainRoom),并重新订阅所有新的。这是自动完成的。

如果我需要完全取消订阅所有人怎么办?

当您订阅时,您已经返回了一个IDisposable,如果调用会自动为您取消订阅所有内容,从而释放所有事件。

[Fact]
public void ShouldNotNotifyIfDisposed()
{
    var house = new House
    {
        MainRoom = new Room
        {
            Table = new()
        }
    };

    var counter = 0;
    var subscription = house
        .WhenChanged(h => h.MainRoom.Table)
        .With<propertychangeobserver>()
        .Do(() => counter++);

    subscription.Dispose();
    house.MainRoom = new();
    counter.Should().Be(0);
}

https://www.codeproject.com/Tips/5338061/Fluent-Expression-Tree-Binding-in-MVVM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值