简体   繁体   中英

Adding Items to Collection using MVVM pattern

I am having truble accessing ObservableCollection (which is my ItemsSource) from command attached to each of the items.

I am trying make two list, one with all the objects and the second one with objects picked by user.

Here is my view model.

class ViewModel : VMBase
{
    private ObservableCollection<Card> _cardsCollection;
    public ObservableCollection<Card> CardsCollection
    {
        get { return _cardsCollection; }
        set { _cardsCollection = value; }
    }

    static private ObservableCollection<Card> _pickedCards;
    static public ObservableCollection<Card> PickedCards
    {
        get { return _pickedCards; }
        set { _pickedCards = value;
              NotifyPropertyChanged("PickedCards");
            }
    }
}
class Card : VMBase
{
    public string Name { get; set; }
    public Card(string name, int cost, CardType type, CardRarity rarity)
    {
        this.Name = name;
        this.BackgroundImage = String.Format("/Images/Cards/{0}.png", name);

        this.PickCardCommand = new MvvmCommand();
        this.PickCardCommand.CanExecuteFunc = obj => true;
        this.PickCardCommand.ExecuteFunction = PickCard;
    }
    public MvvmCommand PickCardCommand { get; set; }
    public void PickCard(object parameter)
    {
        PickedCards.Add(currentCard); 
        //Above Does not work, not accessible
        CreateDeckModel.PickedCards.Add(currentCard);
        //Above does work but only if Collection is static
        //but if collection is static I am unable to call NotifyPropertyChanged()
    }
}

Here is my XAML file with binding

<GridView Grid.Row="1" ItemsSource="{Binding CardsCollection, Mode=TwoWay}">
     <GridView.ItemTemplate>
         <DataTemplate>
             <Grid>
                  <Button Height="258" Width="180" Content="{Binding}" Margin="0,0,0,0" 
                          Command="{Binding PickCardCommand}" CommandParameter="{Binding}">
                      <Button.Template>
                          <ControlTemplate>
                              <StackPanel Orientation="Vertical">
                                  <Border BorderThickness="2" BorderBrush="White" Height="258" Width="180">
                                      <Border.Background>
                                          <ImageBrush ImageSource="{Binding BackgroundImage}" />
                                      </Border.Background>
                                   </Border>
                              </StackPanel>
                          </ControlTemplate>
                       </Button.Template>
                   </Button>
               </Grid>
           </DataTemplate>
       </GridView.ItemTemplate>
   </GridView>

Here is my MvvmCommand Class

class MvvmCommand : ICommand
{
    public Predicate<object> CanExecuteFunc { get; set; }
    public Action<object> ExecuteFunction { get; set; }
    public void Execute(object parameter)
    {
        ExecuteFunction(parameter);
    }

    public event EventHandler CanExecuteChanged;
    public bool CanExecute(object parameter)
    {
        return CanExecuteFunc(parameter);
    }
}

}

Is there a way to access ItemsSource from Item or DataContext alternatively make command accessible for ViewModel Class?

You can point the Command to your ViewModel class by changing the button in your xaml file to the following:

<Button Height="258" Width="180" Content="{Binding}" Margin="0,0,0,0" Command="{Binding DataContext.PickCardCommand,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type vw:ViewClass}}}" CommandParameter="{Binding}">

In the RelativeSource binding you will need to change the following:

vw is the namespace for your View, this will have to be declared with the other namespaces in your xaml file.

ViewClass is the name of your class.

Then you obviously need to move the Command over to the ViewModel class from your Card class.

Windows Phone

<GridView x:Name="myGridView" Grid.Row="1" ItemsSource="{Binding CardsCollection, Mode=TwoWay}">
     <GridView.ItemTemplate>
         <DataTemplate>
             <Grid>
                  <Button Height="258" Width="180" Content="{Binding}" Margin="0,0,0,0" 
                          Command="{Binding ElementName=myGridView,
                   Path=DataContext.PickCardCommand}" CommandParameter="{Binding}">
                      <Button.Template>
                          <ControlTemplate>
                              <StackPanel Orientation="Vertical">
                                  <Border BorderThickness="2" BorderBrush="White" Height="258" Width="180">
                                      <Border.Background>
                                          <ImageBrush ImageSource="{Binding BackgroundImage}" />
                                      </Border.Background>
                                   </Border>
                              </StackPanel>
                          </ControlTemplate>
                       </Button.Template>
                   </Button>
               </Grid>
           </DataTemplate>
       </GridView.ItemTemplate>
   </GridView>

You will see that I have now named the GridView and then used the name of the GridView in the binding as the ElementName. I believe this should work.

You can just pass the Add method of PickedCards to the Card when you create it:

class Card : VMBase
{
    private readonly Action<Card> _addCard;

    public Card(..., Action<Card> addCard)
    {
        ...
        _addCard = addCard;

        this.PickCardCommand = new MvvmCommand();
        this.PickCardCommand.CanExecuteFunc = obj => true;
        this.PickCardCommand.ExecuteFunction = PickCard;
    }

    public MvvmCommand PickCardCommand { get; set; }

    public void PickCard(object parameter)
    {
        _addCard(this);
    }
}

Then when you create the card:

var card = new Card(..., ..., ..., ..., PickedCards.Add)

You can bind your collection to the Command parameter. Command parameter is currently bound to Item DataSource and not collection

CommandParameter="{Binding}"

Instead use RelativeBinding and bind to itemSource of grid

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