2

I can't bind to my ObservableCollection<T> within my ListBox.

I am using MVVM, WPF.

The binding for the page works. My understanding is, the Grid (not shown in code) is bound to my DataContext, which is my ViewModel. Therefore, my ListBox can bind to my object called Folders via the Itemssource. My Folders object is very simple, it is literally

private ObservableCollection<Folders> _folders;
public ObservableCollection<Folders> Folders 
{
get { return _folders; }
set
  {
      if (value == _folders)
      return;

      _folders = value;
      OnPropertyChanged("Folders");
   }
}

and my Folders model is

public class Folders
{
    public string SourceFolder { get; set; }
    public string DestinationFolder { get; set; }
}

and lastly, my XAML

    <ListBox Grid.RowSpan="2" ItemsSource="{Binding Folders, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" SelectedItem="{Binding SelectedFolderItem}" IsSynchronizedWithCurrentItem="True">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}, AncestorLevel=1}, Path=DataContext}">
                    <StackPanel>
                        <TextBlock Text="{Binding SourceFolder}" />
                        <TextBlock Text="{Binding DestinationFolder}" />
                        <Button Content="Edit" Command="{Binding EditCommand}" CommandParameter="{Binding SelectedListItem}"/>
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

The button binds/executes, but the 2 textblocks do not. I have also tried

 <TextBlock Text="{Binding Folders.SourceFolder}" />
 <TextBlock Text="{Binding Folders.DestinationFolder}" />

but it is the same issue. The content is not displayed (not binding) because if I add a watch on my ViewModel, I can see the values are as they should be.

If it helps, if I update my code to

 <TextBlock Text="{Binding SelectedFolderItem.SourceFolder}" />
 <TextBlock Text="{Binding SelectedFolderItem.DestinationFolder}" />

then it works although this is not desired (it just loops the correct number of times but only for the 1 item!).

Can some one point me in the right direction?

4
  • Why have you changed their data context?
    – user7116
    Commented Jun 12, 2013 at 14:45
  • Without the different datacontext, the button does not execute.
    – Dave
    Commented Jun 12, 2013 at 14:47
  • 1
    You only change the RelativeSource of the bindings which need it as @dowhilefor has pointed out. As a good rule of thumb, if you play with DataContext you're likely doing something wrong.
    – user7116
    Commented Jun 12, 2013 at 14:50
  • @user7116, Thank you, I've just realised this.
    – Dave
    Commented Jun 12, 2013 at 14:51

1 Answer 1

3

You are setting a different DataContext. You don't need that, otherwise you destroy the purpose of the item template.

<StackPanel Orientation="Horizontal">
    <StackPanel>
        <TextBlock Text="{Binding SourceFolder}" />
        <TextBlock Text="{Binding DestinationFolder}" />
        <Button Content="Edit"
                Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.EditCommand}"
                CommandParameter="{Binding}"/>
    </StackPanel>
</StackPanel>

of course if you want the buttons to work aswell, you just move the relative source you currently have to the binding of the button.

8
  • Thank you, but, if I remove the 'second' datacontext, then my Button does not bind/execute. This does resolve my issue, but creates this new one!
    – Dave
    Commented Jun 12, 2013 at 14:47
  • 1
    I updated my answer. Remember that the DataContext is inherited as long as you don't overwrite it, which you did in your original post. But for your command to work, you need that. So you just pass a different Source for the binding, which then ignores the current DataContext.
    – dowhilefor
    Commented Jun 12, 2013 at 14:48
  • Oh wow... I didn't actually understand what the binding was doing... This is like a thousand pennies dropping at once. Beer on me for this, thank you
    – Dave
    Commented Jun 12, 2013 at 14:49
  • Check my code :) Usually Binding works by using the current DataContext, but you can easily change that with ElementName, Source or RelativeSource. In this case we just use RelativeSource to find the ListBox, take the DataContext and bind to its EditCommand property.
    – dowhilefor
    Commented Jun 12, 2013 at 14:51
  • 2
    Why bind to the selected item for the edit button? If you intend for it to edit the current item, just use CommandParameter="{Binding}" which is a shortcut for the current item being templated (-ish).
    – user7116
    Commented Jun 12, 2013 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.