views:

706

answers:

1

I'm new to WPF and data binding so hopefully I can explain the problem I'm having with enough detail to get some help.

I have a list of objects that is data bound to a window. Let's say its a list of recipes. I have managed to get the application to display some details of each recipe in a list box, and some more details of the selected recipe in various text boxes. My problem is that I have a list of ingredients in each recipe that I want to display in another list box when the recipe is selected, but I can't work out how to get the data binding to work.

My data classes look something like:

public class Recipes : ObservableCollection<RecipeDetails>
{
}

public class RecipeDetails
{
    public string Name { get; set; }
    public string Description { get; set; }
    public List<RecipeIngredient> Ingredients;
}

public class RecipeIngredient
{
    public string IngredientName { get; set; }
}


public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        m_recipes = new Recipes();
        // m_recipes initialisation
    }

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

    private Recipes m_recipes;
}

And my data binding attempts (in XAML) look something like:

<Window x:Class="RecipeWindow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Recipe Window" Height="402.687" Width="532.674" Loaded="Window_Loaded">
    <Grid>
        <ListBox Margin="12,58.176,0,16.362" Name="recipeListBox" Width="209.07" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}" FontSize="14" Padding="5" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <StackPanel Margin="245.43,58.176,12,47.268" Name="detailsPanel">
            <TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" Width="140" />
            <TextBox Text="{Binding Description,UpdateSourceTrigger=PropertyChanged}" Width="140" />
            <ListBox Name="ingredientListBox" Width="209.07" ItemsSource="{Binding Ingredients}" Height="118.17">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding IngredientName}" Padding="5" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </Grid>
</Window>

But when I try to run this code, the ingredient list box is always empty. Can anyone tell me what I'm doing wrong?

+4  A: 

The issue is because the way you declare and initialize Ingredients list, Make it as ObservableCollection and initialize the Ingredients collection only in the constructor as following

 public class RecipeDetails
{
    public RecipeDetails()
    {
        _ingredients = new ObservableCollection<RecipeIngredient>();
    }

    public string Name { get; set; }
    public string Description { get; set; }

    private ObservableCollection<RecipeIngredient> _ingredients;

    private ObservableCollection<RecipeIngredient> Ingredients
    {
        get { return _ingredients; }
    }
}

One more point to add to your approach, It is advisable to use INotifyPropertyChanged on this class so that TwoWay binding will be easily achievable here when you type something in the TextBox.

Jobi Joy
Worked like a charm, except I didn't need to initialise it in the constructor. Making it a public property such as: public ObservableCollection<RecipeIngredient> Ingredients { get; set; }seems to be working fine.
Bonnici
Setter on ObservableCollection may give you update issue, if you change it later after DatBinding.
Jobi Joy