防止两个属性相互依赖的死锁

问题描述 投票:0回答:3

如何基于彼此更改两个可观察属性,但防止死锁?

为了这个例子,我保持非常简单:
我正在数两件事,(1)物品和(2)这些物品的容器。每个容器可容纳 3 件物品。用户可以更改物品的数量和容器的数量。更改其中一个会自动更改另一个。

正如你所想象的,这会导致完全的僵局。

显示值:

<Entry Text="{Binding Amount}"/>
<Entry Text="{Binding Sections"/>

设定值:

private int amount;
public int Amount
{
    get => amount;
    set
    {
        SetProperty(ref amount, value);
        Sections = Convert.ToInt32(Math.Round(Amount / 3));
    }
}

private int sections;
public int Sections
{
    get => sections;
    set
    {
        SetProperty(ref sections, value);
        Amount = Sections * 3;
    }
}

如何防止死锁,例如仅在用户调用时更改属性一次?

c# xaml binding deadlock
3个回答
1
投票

您可以实现一个标志,以便只有您正在设置的属性才会触发另一个属性的设置。您设置部分,它会更新部分和金额,但金额不会触发部分更新。

public class TestClass
{
    private bool _updating = false;

    private int _amount;
    public int Amount
    {
        get => _amount;
        set
        {
            _amount = value;
            if (!_updating)
            {
                _updating = true;                 
                Sections = Convert.ToInt32(Math.Round(Convert.ToDouble(Amount / 3)));
                _updating = false;
            }
        }
    }

    private int _sections;
    public int Sections
    {
        get => _sections;
        set
        {
            _sections = value;
            if (!_updating)
            {
                _updating = true;
                Amount = _sections * 3;
                _updating = false;
            }
        }
    }
}

然后您可以调用设置器,而不必担心无限循环:

static void Main()
{
    var tc = new TestClass();

    Console.WriteLine("Set sections = 5");

    tc.Sections = 5;

    Console.WriteLine($"Sections: {tc.Sections}; Amount: {tc.Amount}");

    Console.WriteLine("Set amount = 10");

    tc.Amount = 10;

    Console.WriteLine($"Sections: {tc.Sections}; Amount: {tc.Amount}");
}

产生这个结果:

设置部分 = 5

节数:5; 数量:15

设定数量=10

节数:3; 数量:10


1
投票

创建两个方法来更新属性

void SetAmount(int amount)
{
  this.Amount = amount;
  Sections = Convert.ToInt32(Math.Round(Amount / 3));
}

void SetSections(int sections)
{
  this.Sections = sections;
  Amount = Sections * 3;
}

这样属性设置器就不会递归地互相调用


0
投票

与其拥有两个单独的值并尝试维护它们之间的数据完整性,不如“仅拥有一个存储值”并让其中一个属性完全是计算值。 这不仅意味着不需要递归来解决,而且对象也不可能处于“无效”状态。 private int amount; public int Amount { get => amount; set { SetProperty(ref amount, value); } } public int Sections { get => (int)Math.Round(Amount / 3); set => Amount = Sections * 3; }

	
© www.soinside.com 2019 - 2024. All rights reserved.