Question

So I'm trying to build a small cookbook application using WPF and MVVM light. I've run into a situation where I'm binding a List from the model to the view model. And it works fine for displaying and removing items, but when adding items I couldn't get the display to update.

I came across ObserableCollections which seemed to be just what I wanted, but I'm not sure I'm using them correctly because it seems wrong to be creating a new OC every time. How am I supposed to be retrieving an observable collection when the model is using a list?

Model(s):

public class Recipe
{
    public int Id { get; set; }
    public string Title { get; set; }
    public List<RecipeIngredient> Ingredients { get; set; }
}

public class RecipeIngredient
{
    // ... //
}

ViewModel:

 public Recipe SelectedRecipe
{
    get
    {
        return this.selectedRecipe;
    }
    set
    {
        this.selectedRecipe = value;
        RaisePropertyChanged("SelectedRecipe");
        RaisePropertyChanged("RecipeIngredients");
    }
}

public ObservableCollection<RecipeIngredient> RecipeIngredients
{
    get 
    {
        return new ObservableCollection<RecipeIngredient>(selectedRecipe.Ingredients.ToList());
    }
}

public RelayCommand<EventArgs> AddIngredientCommand { get; private set; }
public RelayCommand<string> DeleteIngredientCommand { get; private set; }

private void AddIngredient(EventArgs eventArgs)
{
    SelectedRecipe.Ingredients.Add(new RecipeIngredient() { Name = "New Ingredient" }); 
    RaisePropertyChanged("RecipeIngredients");
}

private void DeleteIngredient(string name)
{
    SelectedRecipe.Ingredients = SelectedRecipe.Ingredients.Where(i => i.Name != name).ToList();
    RaisePropertyChanged("RecipeIngredients");
}

public MainViewModel()
{
    DBController db = new DBController();
    recipes = db.GetRecipeList();

    RecipeSelectionChangedCommand = new RelayCommand<SelectionChangedEventArgs>((args) => RecipeSelectionChanged(args));
    SaveRecipeCommand = new RelayCommand<EventArgs>((args) => SaveRecipe(args));    
    AddIngredientCommand = new RelayCommand<EventArgs>((args) => AddIngredient(args));
    DeleteIngredientCommand = new RelayCommand<string>((args) => DeleteIngredient(args));
}

Am I way off track here?

Was it helpful?

Solution

Should have read more carefully. If you're displaying the selected recipe's ingredients in an alternate view, you should be using data binding in the view <ListBox ItemsSource="{Binding SelectedRecipe.Ingredients}"/> You could consider using linq to entities (Entity Framework) for ORM..

public class RecipeVM
{
    public RecipeVM(Recipe r)
    {
        recipe = r;
    }
    Recipe recipe;
    public int Id 
    { 
        get
        {
            return recipe.Id;
        }
        set
        {
            PropertyChanged("Id");
            recipe.id = value;
        }
    }
    public string Title
    {
        get
        {
            return recipe.Title;
        }
        set
        {
            PropertyChanged("Title");
            recipe.Title = value;
        }
    }
    ObservableCollection<RecipeIngredient> ingredients;
    public ObservableCollection<RecipeIngredient> Ingredients 
    {
        get
        {
            if (ingredients == null)
                ingredients = new ObservableCollection<RecipeIngredient>(recipe.Ingredients);
            return ingredients;
        }
        set
        {
            PropertyChanged("Ingredients");
            ingredients = value;
        }
    }
}

You'll need to modify that a bit if you want to keep the collections in sync though..

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top