【问题标题】:ObservableCollection that fires when containing items change包含项目更改时触发的 ObservableCollection
【发布时间】:2015-11-19 11:50:41
【问题描述】:

我发现这个话题对这里的很多人来说都是一个真正的难题,因此它实际上被很好地覆盖了!尽管如此,提供的解决方案似乎都不适合我。

正如标题所说,它是关于 ObservableCollection 在 item 的值更改时不会触发的问题,只有当 Item 本身 以某种方式被删除、添加或更改时。

我尝试了使用 BindingList 的解决方案——尽管很多人不建议它——但它没有用,像 here 解释的带有扩展 ObservableCollections 的解决方案。它似乎都不起作用......这就留下了错误是我认为它在哪里还是完全在其他地方的问题!

好的,这是我的代码:

基类:

public class ModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propName = "")
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

class TestSensor : ModelBase
{


    private bool isOnline;
    public bool IsOnline
    {
        get
        {
            return isOnline;
        }
        set
        {
            if (isOnline != value)
            {
                isOnline = value;
                this.OnPropertyChanged();
            }
        }
    }


    private double sensorDatauStrain;
    public double SensorDatauStrain
    {
        get { return sensorDatauStrain; }
        set
        {
            if (sensorDatauStrain != value)
            {
                sensorDatauStrain = value;
                this.OnPropertyChanged();
            }
        }
    }


    private double sensorDatakNewton;
    public double SensorDatakNewton
    {
        get { return sensorDatakNewton; }
        set
        {
            if (sensorDatakNewton != value)
            {
                sensorDatakNewton = value;
                this.OnPropertyChanged();
            }
        }
    }


    private double sensorDataTon;
    public double SensorDataTon
    {
        get { return sensorDataTon; }
        set
        {
            if (sensorDataTon != value)
            {
                sensorDataTon = value;
                this.OnPropertyChanged();
            }
        }
    }


    private double sensorDatausTon;
    public double SensorDatausTon
    {
        get { return sensorDatausTon; }
        set
        {
            if (sensorDatausTon != value)
            {
                sensorDatausTon = value;
                this.OnPropertyChanged();
            }
        }
    }

    private string sensorName;
    public string SensorName
    {
        get { return sensorName; }
        set
        {
            if (sensorName != value)
            {
                sensorName = value;
                this.OnPropertyChanged();
            }
        }
    }

    public TestSensor(string name, double ustrain,double kNewton, double ton, double uston)
    {
        this.SensorName = name;
        this.SensorDatauStrain = ustrain;
        this.SensorDatakNewton = kNewton;
        this.SensorDataTon = ton;
        this.SensorDatausTon = uston;
        this.IsOnline = true;
    }
 }

然后我有一个包含这些传感器的类:

class Holm : ModelBase
{
    public Holm(String Name, TestSensor sensor1, TestSensor sensor2)
    {
        Sensor1 = sensor1;
        Sensor2 = sensor2;
        this.Name = Name;
    }


    private string name;
    public string Name
    {
        get
        {
            return name;
        }

        set
        {
            if (name != value)
            {
                name = value;
                this.OnPropertyChanged();
            }
        }
    }

    private TestSensor sensor1;
    public TestSensor Sensor1
    {
        get
        {
            return sensor1;
        }
        set
        {
            if (sensor1 != value)
            {
                sensor1 = value;
                this.OnPropertyChanged();
            }
        }
    }

    private TestSensor sensor2;
    public TestSensor Sensor2
    {
        get
        {
            return sensor2;
        }
        set
        {
            if (sensor2 != value)
            {
                sensor2 = value;
                this.OnPropertyChanged();
            }

        }
    }

    public bool IsOnline
    {
        get
        {
            if (!Sensor1.IsOnline || !Sensor2.IsOnline)
            {
                return false;
            }
            else
            {
                return true;
            }

        }

    }

 }

最后是包含我失败的 ObservableCollection 的 ViewModel - 不包括一些不相关的东西:

    class MainViewViewModel : ModelBase
    {

           public ItemsChangeObservableCollection<Holm> HolmList { get;set;}

              public MainViewViewModel()
            {  

            Sensor11 = new TestSensor("Sensor 1.1", 0, 0, 0, 0);
            Sensor12 = new TestSensor("Sensor 1.2", 0, 0, 0, 0);
            Sensor21 = new TestSensor("Sensor 2.1", 0, 0, 0, 0);
            Sensor22 = new TestSensor("Sensor 2.2", 0, 0, 0, 0);
            Sensor31 = new TestSensor("Sensor 3.1", 0, 0, 0, 0);
            Sensor32 = new TestSensor("Sensor 3.2", 0, 0, 0, 0);
            Sensor41 = new TestSensor("Sensor 4.1", 0, 0, 0, 0);
            Sensor42 = new TestSensor("Sensor 4.2", 0, 0, 0, 0);


            Holm1 = new Holm("Holm 1", Sensor11, Sensor12);
            Holm2 = new Holm("Holm 2", Sensor21, Sensor22);
            Holm3 = new Holm("Holm 3", Sensor31, Sensor32);
            Holm4 = new Holm("Holm 4", Sensor41, Sensor42);

            HolmList = new ItemsChangeObservableCollection<Holm>();
            HolmList.Add(Holm1);
            HolmList.Add(Holm2);
            HolmList.Add(Holm3);
            HolmList.Add(Holm4);

             }


    private TestSensor sensor11;
    public TestSensor Sensor11
    {
        get { return sensor11; }
        set
        {
            if (sensor11 != value)
            {
                sensor11 = value;
                this.OnPropertyChanged();
                this.OnPropertyChanged("Holm1");
                this.OnPropertyChanged("HolmList");
            }
        }
    }
    private TestSensor sensor12;
    public TestSensor Sensor12
    {
        get { return sensor12; }
        set
        {
            if (sensor12 != value)
            {
                sensor12 = value;
                this.OnPropertyChanged();
                this.OnPropertyChanged("Holm1");
                this.OnPropertyChanged("HolmList");
            }
        }
    }



    private TestSensor sensor21;
    public TestSensor Sensor21
    {
        get { return sensor21; }
        set
        {
            if (sensor21 != value)
            {
                sensor21 = value;
                this.OnPropertyChanged();
            }
        }
    }
    private TestSensor sensor22;
    public TestSensor Sensor22
    {
        get { return sensor22; }
        set
        {
            if (sensor22 != value)
            {
                sensor22 = value;
                this.OnPropertyChanged();

            }
        }
    }


    private TestSensor sensor31;
    public TestSensor Sensor31
    {
        get { return sensor31; }
        set
        {
            if (sensor31 != value)
            {
                sensor31 = value;
                this.OnPropertyChanged();

            }
        }
    }
    private TestSensor sensor32;
    public TestSensor Sensor32
    {
        get { return sensor32; }
        set
        {
            if (sensor32 != value)
            {
                sensor32 = value;
                this.OnPropertyChanged();

            }
        }
    }


    private TestSensor sensor41;
    public TestSensor Sensor41
    {
        get { return sensor41; }
        set
        {
            if (sensor41 != value)
            {
                sensor41 = value;
                this.OnPropertyChanged();
                                }
        }
    }
    private TestSensor sensor42;
    public TestSensor Sensor42
    {
        get { return sensor42; }
        set
        {
            if (sensor42 != value)
            {
                sensor42 = value;
                this.OnPropertyChanged();
                                }
        }
    }



    private Holm holm1;
    public Holm Holm1
    {
        get
        {
            return holm1;
        }
        set
        {
            if (holm1 != value)
            {
                holm1 = value;
                this.OnPropertyChanged();
                this.OnPropertyChanged("HolmList");
            }
        }
    }

    private Holm holm2;
    public Holm Holm2
    {
        get
        {
            return holm2;
        }
        set
        {
            if (holm2 != value)
            {
                holm2 = value;
                this.OnPropertyChanged();
            }
        }
    }
    private Holm holm3;
    public Holm Holm3
    {
        get
        {
            return holm3;
        }
        set
        {
            if (holm3 != value)
            {
                holm3 = value;
                this.OnPropertyChanged();
            }
        }
    }
    private Holm holm4;
    public Holm Holm4
    {
        get
        {
            return holm4;
        }
        set
        {
            if (holm4 != value)
            {
                holm4 = value;
                this.OnPropertyChanged();
            }
        }
    }
  }

Xaml 并不重要,还没有完成。到目前为止,我已经用这段代码解决了这个问题:

<CheckBox Content="Sensor1.1" IsChecked="{Binding HolmList[0].Sensor1.IsOnline}"/>
<TextBlock Text="{Binding HolmList[0].Sensor1.IsOnline, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<CheckBox Content="Sensor1.2" IsChecked="{Binding HolmList[0].Sensor2.IsOnline}"/>
<TextBlock Text="{Binding HolmList[0].Sensor2.IsOnline, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="{Binding HolmList[0].IsOnline, UpdateSourceTrigger=PropertyChanged}" />

只要其中一个传感器 IsOnline-Property 更改为 false,我想要的只是 Holms IsOnline-Property 更改为 false...但它不会!

知道这是很多代码,但我实际上不确定错误在哪里。 另外:在我看来,我的班级对 OnPropertyChange() 有多余的调用......但我不确定。

我真的很感谢在这方面的各种帮助!!!

【问题讨论】:

  • 看起来您想要实现的目标与可观察的集合完全无关。 Holm.IsOnline 取决于其传感器是否在线,因此 Holm 应该只监听来自其传感器的 IsOnline 属性更改事件,并通过为其自己的 IsOnline 属性引发属性更改事件来对此作出反应。
  • 没有错误,提到的列表/集合都没有提供此功能。而且由于您的解决方案不是手动执行的,因此您的 IsOnline 属性设置正确。你只需要手动监听Sensor.IsOnline变化的property-changed-event,并相应地更新Holm.IsOnline
  • 非常感谢您的快速回复。我还不是很擅长整个订阅和退订部分,因此如果有人可以发布几行示例代码,我会非常高兴?!我尝试过一些教程,但我无法正确理解...

标签: c# wpf xaml observablecollection inotifypropertychanged


【解决方案1】:

绑定到 HolmList[0].IsOnline 的 TextBlock 未更新,因为 Holm 上的 IsOnline 未通知其值已更改。
您可以在TestSensor 中收听TestSensorPropertyChanged 事件,并在TestSensorIsOnline 属性之一发生更改时通知IsOnline 属性更改。

class Holm : ModelBase
{
    public Holm(String Name, TestSensor sensor1, TestSensor sensor2)
    {
        Sensor1 = sensor1;
        Sensor2 = sensor2;
        this.Name = Name;

        Sensor1.PropertyChanged += OnSensorOnlineChanged;
        Sensor2.PropertyChanged += OnSensorOnlineChanged;
    }

    private void OnSensorOnlineChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "IsOnline")
        {
            OnPropertyChanged(nameof(IsOnline));
        }
    }
}

nameof keyword

【讨论】:

  • 谢谢!第一个真正有效的解决方案!很好的帮助!
  • 为了避免内存泄漏,需要有清理代码,您可以在其中取消订阅 OnSensorOnlineChanged 事件 - 如 Dbl 的回答。
  • @NoMoreQuestions 你是对的。但是它也取决于事件生产者的范围,因此我们并不总是需要取消订阅。
【解决方案2】:

你的意思是这样的?

public class EnhancedObservableCollection<T> : ObservableCollection<T>
    where T : INotifyPropertyChanged
{
    public EnhancedObservableCollection(bool isCollectionChangedOnChildChange)
    {
        IsCollectionChangedOnChildChange = isCollectionChangedOnChildChange;
    }

    public EnhancedObservableCollection(List<T> list, bool isCollectionChangedOnChildChange) : base(list)
    {
        IsCollectionChangedOnChildChange = isCollectionChangedOnChildChange;
    }

    public EnhancedObservableCollection(IEnumerable<T> collection, bool isCollectionChangedOnChildChange) : base(collection)
    {
        IsCollectionChangedOnChildChange = isCollectionChangedOnChildChange;
    }

    public bool IsCollectionChangedOnChildChange { get; set; }

    public event EventHandler<string> ChildChanged;

    protected override void RemoveItem(int index)
    {
        var item = Items[index];
        item.PropertyChanged -= ItemOnPropertyChanged;
        base.RemoveItem(index);
    }

    private void ItemOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
    {
        var handler = ChildChanged;
        if (handler != null)
        {
            handler(this, propertyChangedEventArgs.PropertyName);
        }
        if (IsCollectionChangedOnChildChange)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace));
        }
    }

    protected override void InsertItem(int index, T item)
    {
        base.InsertItem(index, item);
        item.PropertyChanged += ItemOnPropertyChanged;
    }
}

【讨论】:

  • 谢谢!但结果与我在问题中链接的解决方案相同:它看起来正是我需要的......但不知何故不起作用! HolmList[0].IsOnline 的值没有改变......你没有覆盖 add-method 的原因是什么?
  • @Laurence 我通常会覆盖插入,因为某些集合提供添加以在末尾附加到列表或在特定位置插入。在这两种情况下都将调用覆盖的 inserItem。通常我会去消息来源确认:)
猜你喜欢
  • 2011-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-05
  • 1970-01-01
  • 2013-06-15
  • 2012-10-25
  • 2021-12-03
相关资源
最近更新 更多