0

I am learning and creating my first WPF application attempting to Implement the MVVM design pattern, however I cannot seem to work out why this property is not firing its Set Accessor, so I can make use of the OnPropertyChanged Method I have. Would really appreciate an explanation as to why this is not working as I expected.

The part I do not understand is that in the GetChargeUnits method in the ViewModel I am creating an instance of my Charge Unit Model and setting the Property to be the result of the reader (This reader does return a result) The Property sets fine? But when stepping through it never hits the Set line in the property so I cannot detect if it has changed. The part commented in this method was what I had originally I have tried many combinations.

Please help, thanks

Model:

public class ChargeUnit : INotifyPropertyChanged
{
    private string _chargeUnitDescription;
    private int _chargeUnitListValueId;
    public event PropertyChangedEventHandler PropertyChanged;

    public ChargeUnit()
    {

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

    public string ChargeUnitDescription
    {
        get { return _chargeUnitDescription; }
        set
        {
            _chargeUnitDescription = value;
            OnPropertyChanged("ChargeUnitDescription");
        }
    }

    public int ChargeUnitListValueId
    {
        get { return _chargeUnitListValueId; }
        set
        {
            _chargeUnitListValueId = value;
            OnPropertyChanged("ChargeUnitListValueId");
        }
    }

ViewModel:

public class ClientRatesViewModel
{
    private IList<ClientRates> _clientRatesPreAwr;
    private IList<ClientRates> _clientRatesPostAwr;
    private List<ChargeUnit> _chargeUnits;
    private const string _connectionString = @"connectionString....";
    public ClientRatesViewModel()
    {
        _clientRatesPreAwr = new List<ClientRates>
        {
            new ClientRates {ClientRatesPreAwr = "Basic"}
        };

        _clientRatesPostAwr = new List<ClientRates>
        {
            new ClientRates{ClientRatesPostAwr = "Basic Post AWR"}
        };

        _chargeUnits = new List<ChargeUnit>();
    }

    public IList<ClientRates> ClientRatesPreAwr
    {
        get { return _clientRatesPreAwr; }
        set { _clientRatesPreAwr = value; }
    }

    public IList<ClientRates> ClientRatesPostAwr
    {
        get { return _clientRatesPostAwr; }
        set { _clientRatesPostAwr = value; }
    }

    public List<ChargeUnit> ChargeUnits
    {
        get { return _chargeUnits; }
        set { _chargeUnits = value; }
    }

    public List<ChargeUnit> GetChargeUnits()
    {
        using (var connection = new SqlConnection(_connectionString))
        {
            connection.Open();
            using (var command = new SqlCommand("SELECT LV.ListValueId, LV.ValueName FROM tablename", connection))
            {
                command.CommandType = CommandType.Text;

                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        var test = new ChargeUnit();
                        test.ChargeUnitDescription = reader["ValueName"].ToString();
                        //_chargeUnits.Add(new ChargeUnit
                        //{
                        //    ChargeUnitDescription = reader["ValueName"].ToString(),
                        //    ChargeUnitListValueId = (int)reader["ListValueId"]
                        //});
                    }
                }


            }

        }
        return new List<ChargeUnit>();
    }
David B
  • 889
  • 2
  • 11
  • 29
  • 1
    Have you checked your VS settings for getters and setters? This is for VS 2013 but you probably can Google that for other versions. Go to Tools -> Options -> Debugging -> General. Then on the right side uncheck "Step over properties and operators (Managed only)" – Frank J Mar 30 '15 at 20:23
  • 1
    @FrankJ You cracked it! Thanks a lot – David B Mar 30 '15 at 20:47
  • @FrankJ Just realised this was part the issue, as it is jumping into the set now, when I set it in the ViewModel, however when I change the value in the combobox the ChargeUnitDescription Property in my Model never reaches the Set, however it does always return the Updated Value I have just selected? – David B Mar 31 '15 at 14:56
  • Have you set a breakpoint into the Setter code? Binding propagated changes are not easily observable while stepping through code only. You need a breakpoint. If that doesn't work post a minimal code example that I can run in VS and describe the steps of what you are doing, what is happening and what you would expect to be happening based on the example. – Frank J Mar 31 '15 at 15:14
  • @FrankJ If you refer back to the model I posted above, there is a breakpoint in the setter of the ChargeUnitDescription. This never gets hit, when I select any item in my combobox. However the get gets hit everytime and the _chargeUnitDescription contains the ChargeUnitDescription displayed in the combobox. My Xaml comboboxs displaymemberpath is also this Property (ChargeUnitDescription) – David B Mar 31 '15 at 16:01

1 Answers1

0

I think there is a misunderstanding.

Think about it that way: Why would ChargeUnitDescription in your Model change? You are not changing the content of that property.

What you describe is, you are changing the SelectedItem of your ComboBox. The get of your model instance get's hit because the ComboBox needs to access it to display the string as you defined it in your binding with the DisplayMemberPath property of the ComboBox.

What you are interested in is the SelectedItem orSelectedValue (depending on your setup) of the ComboBox.

Here is a minimal example to illustrate this:

    namespace SOBindingTest1
{
    public partial class MainWindow : Window
    {
        public ClientRatesViewModel crvm { get; set; }
        public MainWindow()
        {
            InitializeComponent();
            crvm = new ClientRatesViewModel();
        }


        public class ChargeUnit : INotifyPropertyChanged
        {
            private string _chargeUnitDescription;
            private int _chargeUnitListValueId;

            public ChargeUnit()
            {

            }

            public string ChargeUnitDescription
            {
                get { return _chargeUnitDescription; }
                set
                {
                    _chargeUnitDescription = value;
                    OnPropertyChanged();
                }
            }

            public int ChargeUnitListValueId
            {
                get { return _chargeUnitListValueId; }
                set
                {
                    _chargeUnitListValueId = value;
                    OnPropertyChanged();
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
            {
                PropertyChangedEventHandler tmp = this.PropertyChanged;
                if (tmp != null)
                {
                    tmp(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }

        public class ClientRatesViewModel : INotifyPropertyChanged
        {
            public ClientRatesViewModel()
            {
                _chargeUnits = new List<ChargeUnit>();
                for (int i = 0; i < 10; i++)
                {
                    _chargeUnits.Add(new ChargeUnit() { ChargeUnitDescription = i.ToString(), ChargeUnitListValueId = i });
                }
            }

            protected ChargeUnit _SelectedItem;
            public ChargeUnit SelectedItem
            {
                get
                {
                    return this._SelectedItem;
                }
                set
                {
                    if(this._SelectedItem == value)
                    {
                        return;
                    }
                    this._SelectedItem = value;
                    this.OnPropertyChanged();
                }
            }


            private List<ChargeUnit> _chargeUnits;
            public List<ChargeUnit> ChargeUnits
            {
                get { return _chargeUnits; }
                set 
                {
                    if(this._chargeUnits == value)
                    {
                        return;
                    }
                    _chargeUnits = value;
                    this.OnPropertyChanged();
                }
            }

            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
            {
                PropertyChangedEventHandler tmp = this.PropertyChanged;
                if (tmp != null)
                {
                    tmp(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    }
}   

And the corresponding xaml:

<Window x:Class="SOBindingTest1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:SOBindingTest1"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
      <Grid.RowDefinitions>
         <RowDefinition Height="Auto"/>
         <RowDefinition Height="*"/>
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="*" />
         <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <TextBlock Text="Bla:"  HorizontalAlignment="Right" Margin="10"/>
      <ComboBox Name="cboTest" Grid.Column="1" Margin="3" DisplayMemberPath="ChargeUnitDescription" SelectedValuePath="ChargeUnitListValueId" ItemsSource="{Binding Path=crvm.ChargeUnits, RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}" SelectedItem="{Binding Path=crvm.SelectedItem, RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"/>
   </Grid>
</Window>

UPDATE:

Changed the code so it fills the selected item into a property of your ViewModel. If you put a breakpoint in the setter it get's hit if you select something in the ComboBox.

For future questions you might ask please provide a Minimal, Complete, and Verifiable example and base your question on that accordingly. That would have saved a lot of time.

UPDATE 2: Added INotifyPropertyChanged to ViewModel example

Community
  • 1
  • 1
Frank J
  • 1,666
  • 13
  • 19
  • Thanks for your help Frank, but I was under the impression handling events would not fall into following the MVVM design pattern. I have seen many posts of binding to a propety and when this value changes the property his the set. This is was doesnt seem to work http://stackoverflow.com/questions/21130850/selection-changed-event-of-combobox-in-wpf-mvvm – David B Apr 01 '15 at 08:32