简体   繁体   中英

ObservableCollection that fires when containing items change

I found this topic to be a real struggle for a lot of people here and it therefore is actually covered pretty good! Nevertheless, none of the provided solutions seems to work for me.

As the title says, its about the problem that ObservableCollection doesnt fire when the value of the item changes, only if the Item itself gets removed, added or changed in some way.

I tried solutions with BindingList- even though a lot of people disadvice it - and it didnt work, solutions with extended ObservableCollections like it is explained here . None of it seems to work...which leaves the question whether the error is where i think it is or somewhere completely else!!

Alright heres my code:

BaseClasses:

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;
    }
 }

Then i have a class containing these Sensors:

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;
            }

        }

    }

 }

And finally the ViewModel that contains my failing ObservableCollection - excluding some things that are not relevant:

    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();
            }
        }
    }
  }

The Xaml isnt really important and is not yet finished. I have solved it so far with this code:

<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}" />

All i want is the Holms IsOnline-Property to change to false as soon as one of the Sensors IsOnline-Property changes to false...but it just wouldnt!

In know this is a lot of code, but im actually not sure where the error is located. Also: It seems to me that my classed have redundant calls to OnPropertyChange()...but im not sure bout it.

Im really thankful for all kind of help on this!!!

you mean something like this?

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;
    }
}

Your TextBlock that bound to HolmList[0].IsOnline didn't update because IsOnline on Holm didn't notify that its value changed.
You can listen to TestSensor 's PropertyChanged event in TestSensor and notify IsOnline property change when one of TestSensor 's IsOnline property change.

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));
        }
    }
}

The nameof keyword

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM