Lost
Lost

Reputation: 13645

Setter not called when a control bound to Array element changes the value

I am new to WPF and bindings and I wanted to see if there is a way to do a two way binding between an array element and a control:

My ViewModel has a property which looks like following:

public ObservableCollection<MeaseurementValue> MeasurementValues
        {
            get
            {
                return Config.MeasurementValues;
            }
            set
            {
                if (value == null) return;
                Config.MeasurementValues = value;
                OnPropertyChanged("MeasurementValues");
                QpatConfig.SerializeConfigFile(Config,
                    Path.GetPathRoot(Environment.GetFolderPath(Environment.SpecialFolder.System)) + "//Qualcomm//QPAT//qpat.config");              
            }
        }

Where MeasurementValues is defined as following:

public class MeaseurementValue
    {
      public string TestName { get; set; }
      public int value { get;set; }
    }

Xaml looks like following:

 <TextBox HorizontalAlignment="Left" Grid.Column="1"   Grid.Row="1"   Height="23" Margin="14,20,0,0" TextWrapping="Wrap" Text="{Binding MeasurementValues[0].value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="124"  />

So the element in the xaml is bound to an Arrayelement in ViewModel. But when I change that property in text control it does not call the setter of the ViewModel.

I also changed my code that evey element in the array is also notifiable so it looks like following:

public class MeaseurementValue : INotifyPropertyChanged
    {
      public event PropertyChangedEventHandler PropertyChanged;
      public string TestName { get; set; }    

      private int _value;
      public int value
      {
          get { return _value; }
          set { _value = value; OnPropertyChanged("value"); }
      }

      void OnPropertyChanged(string propertyName)
      {
          var handler = PropertyChanged;
          if (handler != null)
          {
              handler(this, new PropertyChangedEventArgs(propertyName));
          }
      }
    }

But that also did not work

Is that anything different that we have to do with Arrays as oppose to primitive types?

Upvotes: 0

Views: 1413

Answers (1)

Eli Arbel
Eli Arbel

Reputation: 22749

The setter gets called, just not the one you expect. In two-way bindings, only the last property in the path gets updated (in the target->source direction).

Think of it like this - if you wrote it in C#, what would you expect to happen?

MeasurementValues[0].value = 1;

What happens here is that first the MeasurementValues getter is called, then the array indexer's getter is called, but the setter is of the value property. So there's no reason for the array's setter to ever be called. You're two property accessors away from the MeasurementValues setter. Even if you write

MeasurementValues[0] = new MeasurementValue();

the MeasurementValues setter won't be called. Only

MeasurementValues = new ObservableCollection<MeaseurementValue>();

would cause the setter you're referring to be called. It's the exact same thing with bindings. The last item in the property path is the only setter used in a two-way binding. In your case it's the value property.

If you want to save the configuration each time the value property is set, you can:

  • Create a ValueChanged event in MeaseurementValue and hook it up when you create each item
  • Use some pub/sub mechanism (such as Prism's Event Aggregator) to publish that the value has changed

Upvotes: 2

Related Questions