简体   繁体   中英

WPF Combobox not updating when collection is changed

I am new to WPF.

I am trying to bind collection of string to combobox.

public ObservableCollection<string> ListString {get; set;}

Binding and datacontext are set as follows

<Window 
        x:Class="Assignment2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:validators="clr-namespace:Assignment2"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}, Path=.}">
    <Grid>
        <ComboBox  Height="23" HorizontalAlignment="Left" Margin="109,103,0,0" Name="StringComboBox" VerticalAlignment="Top" Width="120" SelectionChanged="StringComboBox_SelectionChanged">
            <ComboBox.ItemsSource>
                <Binding Path="ListString" BindsDirectlyToSource="True" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"></Binding>
            </ComboBox.ItemsSource>
        </ComboBox>

I came to know that this is happening because collection is updating. If I write

public MainWindow()
        {

            InputString = "";
            ListString = new ObservableCollection<string>();
            ListString.Add("AAA");
            ListString.Add("BBB");
            ListString.Add("CCC");
          InitializeComponent();

        }

It does work but if I am move InitializeComponent() above at first line as follows, it doesn't work.

  public MainWindow()
            {
               InitializeComponent();
                InputString = "";
                ListString = new ObservableCollection<string>();
                ListString.Add("AAA");
                ListString.Add("BBB");
                ListString.Add("CCC");                
            }

What Should I do??

Solved the problem. Implemented INotifyPropertyChanged as follows

public partial class MainWindow : Window, INotifyPropertyChanged

modified the accessors as follows

    private ObservableCollection<string> listString;
    public ObservableCollection<string> ListString 
    {
        get
        {
            return listString;
        }
        set
        {
            listString = value;
            NotifyPropertyChanged("ListString"); // method implemented below
        }
    }

and added the following event and method to raise the event

public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string name)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this,new PropertyChangedEventArgs(name));
    }
}

and it works B)

what happens if you change your code to

<Window 
    x:Class="Assignment2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:validators="clr-namespace:Assignment2"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <ComboBox  Height="23" HorizontalAlignment="Left" Margin="109,103,0,0" Name="StringComboBox" VerticalAlignment="Top" Width="120" SelectionChanged="StringComboBox_SelectionChanged"
               ItemsSource="{Binding ListString, Mode=OneWay}"/>

cs.

  public MainWindow()
        {
           InitializeComponent();
            InputString = "";
            ListString = new ObservableCollection<string>();
            ListString.Add("AAA");
            ListString.Add("BBB");
            ListString.Add("CCC"); 

           this.DataContext=this;    
      }           

btw: setting the ItemsSource with mode=twoway makes no sense to me. your combobox will never "create a new itemssource" for your viewmodel.

EDIT: i think your first solution works because of setting the DataContext in xaml. i assume that DataContext="{Binding RelativeSource={RelativeSource Self}, Path=.}" is execute when calling InitializeComponent(); and because your ListString property is just an autoproperty and not implement INotifyPropertyChanged - your mainwindowview does not get notified that your ctor creates a new ListString property.

  public ObservableCollection<string> ListString {get{return _list;}; set{_list=value; OnPropertyChanged("ListString");}}

should work with both of your approaches, but you have to implement INotifyPropertyChanged for your MainWindow class.

You can set the item source for combobox in code behind or set datacontext again after your list is populated or you can go with inotifychanged to raise property change.

public MainWindow()
        {
            InitializeComponent();
            InputString = "";
            ListString = new ObservableCollection<string>();
            ListString.Add("AAA");
            ListString.Add("BBB");
            ListString.Add("CCC");
            StringComboBox.ItemsSource = ListString;

        }

Seems to me the problem was "newing up" ListString . Making it a property (the selected answer) is one way around that. Alternatively inlining the instantation, or putting it before InitializeComponent I believe would be ok.

If newing up is expected to occur often it might be helpful to encapsulate the ObservableCollection in a manager class. I found this question after troubleshooting my own issues with such a setup. I got it working by implementing INotifyCollectionChanged and forwarding the event like so

/// <summary>
/// Maintains an observable (i.e. good for binding) collection of resources that can be indexed by name or alias
/// </summary>
/// <typeparam name="RT">Resource Type: the type of resource associated with this collection</typeparam>
public class ResourceCollection<RT> : IEnumerable, INotifyCollectionChanged
    where RT : class, IResource, new()
{
    public event NotifyCollectionChangedEventHandler CollectionChanged
    {
        add { Ports.CollectionChanged += value; }
        remove { Ports.CollectionChanged -= value; }
    }

    public IEnumerator GetEnumerator() { return Ports.GetEnumerator(); }

    private ObservableCollection<RT> Ports { get; set; }
    private Dictionary<string, RT> ByAlias { get; set; }
    private Dictionary<string, RT> ByName { get; set; }
}

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