1

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?

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

I think his command binding is correct he needs a way to access the parent collection of the items.
If he wants to modify a collection on the parent ViewModel then it would be much cleaner to declare the Command on the ViewModel and modify the collection there.
Unfortunately FindAncestor is not accessible in Windows Phone.
@user2847238 I have updated my answer with a Windows Phone section.
0

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)

Comments

-1

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

2 Comments

let me know if you need help in relative binding
Would be nice if You could help me with it.

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.