0

I have a ComboBox cbo1.

I'm trying to change the item source using the ViewModel with CollectionChanged but the ComboBox items stay blank and won't update.

I've tried several examples and solutions here, but don't know how to implement them right.


XAML

<ComboBox x:Name="cbo1" 
          ItemsSource="{Binding cbo1_Items, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
          SelectedItem="{Binding cbo1_SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
          HorizontalAlignment="Left" 
          Margin="0,0,0,0"
          VerticalAlignment="Top"
          Width="105" 
          Height="22" />

ViewModelBase Class

Bind ComboBox Items

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void Notify(string propName)
    {
        if (this.PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

    public ViewModelBase()
    {
        _cbo1_Items = new ObservableCollection<string>();
        _cbo1_Items.CollectionChanged += cbo1_Items_CollectionChanged;
    }

    // Notify Collection Changed
    //
    public void cbo1_Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        Notify("cbo1_Items");
    }


    // Item Source
    //
    public static ObservableCollection<string> _cbo1_Items = new ObservableCollection<string>();
    public static ObservableCollection<string> cbo1_Items
    {
        get { return _cbo1_Items; }
        set { _cbo1_Items = value; }
    }

    // Selected Item
    //
    public static string cbo1_SelectedItem { get; set; }

}

Example Class

In this class I want to change the ComboBox Item Source.

// Change ViewModel Item Source
//
ViewModelBase._cbo1_Items = new ObservableCollection<string>()
{
    "Item 1",
    "Item 2",
    "Item 3"
};

// ...

// Change Item Source Again
//
ViewModelBase._cbo1_Items = new ObservableCollection<string>()
{
    "Item 4",
    "Item 5",
    "Item 6"
};
Matt McManis
  • 4,475
  • 5
  • 38
  • 93
  • Set the property `cbo1_Items` instead of the backing field `_cbo1_Items`, and fire the PropertyChanged event from the property setters of both the `cbo1_Items` and the `cbo1_SelectedItem` properties. – Clemens Jul 14 '18 at 09:07
  • 1
    And note that setting `Mode=TwoWay` and `UpdateSourceTrigger=PropertyChanged` is pointless on the ItemsSource Binding. It has no effect. Setting it on the SelectedItem Binding is redundant, because these values are already the default. So `ItemsSource="{Binding cbo1_Items}" SelectedItem="{Binding cbo1_SelectedItem}"` is sufficient. – Clemens Jul 14 '18 at 09:08
  • As another note, if you only ever create new item collections instead of adding or removing items to/from an existing collection, then there is no need to use ObservableCollection. – Clemens Jul 14 '18 at 09:13
  • @Clemens I think I got it to work with this https://hastebin.com/epifeduqar.cs. But it is not working with `static`. https://hastebin.com/nageluqale.cs – Matt McManis Jul 14 '18 at 09:35
  • @Clemens I was wrong, it adds the Item Source the first time but will not update when changing the source a second time. – Matt McManis Jul 14 '18 at 09:39
  • 1
    If your properties doesn't need to be static, remove the static modifier. If they need, look here for options on how to bind to static properties. https://stackoverflow.com/questions/936304/binding-to-static-property – Roger Leblanc Jul 14 '18 at 12:50
  • @RogerLeblanc I found a way to make it work, let me know what you think. https://hastebin.com/ojoyovohoy.cs – Matt McManis Jul 14 '18 at 12:54
  • From the code in your comment, your `cbo1_Items` doesn't need to be static, but you might have another reason why this needs to be static. If your code works and it does what you need, then go for it. – Roger Leblanc Jul 14 '18 at 13:05

1 Answers1

1

Implement - RaisePropertyChanged("ComboBoxItemsource");/NotifyPropertyChanged("ComboBoxItemsource") in your property declaration. Ex: -

In View

<ComboBox Width="40" Height="40" ItemsSource="{Binding ComboBoxItemsource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

In View Model-

private ObservableCollection<string> comboBoxItemsource;
 public ObservableCollection<string> ComboBoxItemsource
        {
            get { return comboBoxItemsource; }
            set
            {
                if (comboBoxItemsource != value)
                {
                    comboBoxItemsource = value; 
                    RaisePropertyChanged("ComboBoxItemsource");
                }
            }
        }

    In Class Constructor-

public ClassViewModel()
        {
            ComboBoxItemsource = new ObservableCollection<string>();
            ComboBoxItemsource.Add("Item1");
            ComboBoxItemsource.Add("Item2");
           ....
       }

    //Event on which you want to change the collection

    public void OnClickEvent()
    {
                ComboBoxItemsource = new ObservableCollection<string>();
                ComboBoxItemsource.Add("Item5");
                ComboBoxItemsource.Add("Item6");
    }

Class should Inherit and Implement INotifyPropertyChanged. Hope this Helps..

suraj
  • 196
  • 1
  • 8
  • Before I saw your solution I have got it to work using this. I don't know if it is best practice. Let me know what you think. https://hastebin.com/ojoyovohoy.cs – Matt McManis Jul 14 '18 at 11:15
  • 1
    According to me your solution seems fine to me and there is no issue using in this way. – suraj Jul 16 '18 at 11:14