Sheep
Sheep

Reputation: 47

ListBox does not display the binding data

In my Xaml i have this,

<ComboBox x:Name="masterCB" HorizontalAlignment="Left" Margin="5,127,0,0" VerticalAlignment="Top" Width="106" Height="22" Background="White" ItemsSource="{Binding Masters}" FontSize="11" SelectedIndex="{Binding Action}"/>
        <Label Content="Select Action:" HorizontalAlignment="Left" VerticalAlignment="Top" Height="26" Width="116" Margin="0,151,0,0" Background="{x:Null}" FontWeight="Bold"/>

<ListBox x:Name="actionBox" HorizontalAlignment="Left" Height="250" VerticalAlignment="Top" Width="116" Margin="5,177,0,0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
            ItemsSource="{Binding ActionList}" AlternationCount="2" MouseDoubleClick="actionBox_DoubleClick">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Background="{x:Null}">
                        <TextBlock Text="{Binding}" TextTrimming="WordEllipsis" TextWrapping="Wrap" Height="40" FontSize="11" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
            <ListBox.ItemContainerStyle>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Style.Triggers>
                        <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                            <Setter Property="Background" Value="Silver"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </ListBox.ItemContainerStyle>

In my data class i have this,

private List<String> actionList;
public int Action 
   { 
       get{return this.action;} 
       set
       {
           action = value;
           populateActionList();
       } 
   }
 public List<String> ActionList
   {
       get { return actionList; }
       set { this.actionList = value; }
   private void populateActionList()
   {
       if (this.action == 0)
       {
           actionList = new List<String> { 
       "Chinese",
       "Indian",
       "Malay",
       "Indian",
       };
       if (this.action == 1)
       {
           actionList = new List<String> { 
       "Dog",
       "Cats",
       "Pigs",
       "Horses",
       "Fish",
       "Lion"};
       }
   }

When i do a printline, my actionList is changed, but the ListBox item is not set to my actionList. Would just like to know why and how come the UI does not update? I read somewhere that you would have to change to DataContext and ObservableCollections but i tried that one out and it still does not update. Does anyone know why?

Upvotes: 2

Views: 2290

Answers (4)

Mike Fuchs
Mike Fuchs

Reputation: 12319

In your case, you can also work with Lists if you want, because you are replacing the whole list and not adding/removing single items. For that, you would have to use ObservableCollection, like Jehof wrote, which is automatically firing CollectionChanged events (not PropertyChanged) when add/remove/clear/replace actions are executed on the collection.

You need to change two things to get your code to work:

  1. Correctly implement INotifyPropertyChanged in your viewmodel. For each property that you databind, you will need to fire the PropertyChanged event in the setter. See my code below.
  2. Do not change your private actionList field, instead change your property ActionList, when you want bindings to be updated, because when you change your field, the PropertyChanged event is not fired.

The thing to keep in mind is: Your UI listens to PropertyChanged and CollectionChanged events of the properties it is databound to. So if your UI does not get updated, these events are usually not fired.

ViewModel:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    // Masters
    private List<string> _masters = new List<string>() { "Actions 0", "Actions 1" };
    public List<string> Masters { get { return _masters; } set { _masters = value; OnPropertyChanged("Masters"); } }

    // Action
    private int action;
    public int Action { get { return this.action; } set { action = value; PopulateActionList(); OnPropertyChanged("Action"); } }

    // ActionList
    private List<String> actionList;
    public List<String> ActionList { get { return actionList; } set { this.actionList = value; OnPropertyChanged("ActionList"); } }


    private void PopulateActionList()
    {
        if (this.action == 0)
            this.ActionList = new List<String> { "Chinese", "Indian", "Malay", "Indian" };
        else if (this.action == 1)
            this.ActionList = new List<String> { "Dog", "Cats", "Pigs", "Horses", "Fish", "Lion" };
    }
}

Upvotes: 2

uNople
uNople

Reputation: 554

I copied all of your code, and ran it in a new WPF app.

In order to fix your binding issue, there are two ways:

1st: make a Loaded event on your main window, with the following code:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    DataContext = this;
    populateActionList();
}

this gives the following in my app:

pic of app

2nd: You can also bind this in XAML like so:

in your MainWindow.xaml:

Add the following to the window tag:

DataContext="{Binding RelativeSource={RelativeSource Self}}"

Then in your constructor, make sure you set your data before InitializeComponent() is run:

public MainWindow()
{
   populateActionList();
   InitializeComponent();
}

Upvotes: 2

Jehof
Jehof

Reputation: 35554

Changing your code to the following, will do what you expect

private ObservableCollection<String> _actionList; 

public ObservableCollection<String> ActionList {
  get { 
    if (_actionList == null) {
      _actionList = new ObservableCollection<String>();
    }

    return actionList; 
  }
}

private void populateActionList(){
  if (this.action == 0) {
    ActionList.Clear();

    ActionList.Add("Chinese");
    ActionList.Add("Indian");
    ActionList.Add("Malay");
    ActionList.Add("Indian");
  }

  if (this.action == 1){
    ActionList.Clear();

    ActionList.Add("Dog");
    ActionList.Add("Cats");
    ActionList.Add("Pigs");
    ActionList.Add("Horses");
    ActionList.Add("Fish");
    ActionList.Add("Lion");
  }
}

Upvotes: 3

Mikhail Gubanov
Mikhail Gubanov

Reputation: 420

ActionList should be ObservableCollection<string>.

You should set DataContext of your window to the object with property ActionList

Upvotes: 1

Related Questions