0
votes

How can I bind a command from my IntemsControl list to my main ViewModel?

<Window x:Class="MemoryGame.MainWindow"
        ...
        DataContext="{Binding Main, Source={StaticResource Locator}}">
    <Window.Resources>
        <me:ColorConverter x:Key="ColorConverter"/>
    </Window.Resources>
    <Grid x:Name="LayoutRoot" Background="#FF44494D">
        <ItemsControl ItemsSource="{Binding GameBoard.CardList}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel IsItemsHost="True" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle x:Name="Card01" Fill="{Binding Converter={StaticResource ColorConverter}}" Height="100" Width="100" Margin="10,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Stroke="Black">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Click">
                                <i:InvokeCommandAction Command="{Binding SelectCardCommand, ???????????}" CommandParameter="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </Rectangle>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        ...

SelectCardCommand is defined in my main window ViewModel. I already tryed to add RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window} but it doesn't work.

---- EDIT More information ----

In my DataContext ViewModel I have this :

public class MainViewModel : ViewModelBase
{
    private RelayCommand<string> _selectCardCommand;
    public RelayCommand<string> SelectCardCommand
    {
        get
        {
            return _selectCardCommand;
        }
    }

    public MainViewModel()
    {
        _selectCardCommand = new RelayCommand<string>((s) => DoSelectCardCommand(s));
        // GameBoard = new Board();
        // this.StartGame();
    }

    private void DoSelectCardCommand(string card)
    {
        // Code here
    }
}
1

1 Answers

2
votes

you can use two methods

using RelativeSource

<i:EventTrigger EventName="Click">
    <i:InvokeCommandAction Command="{Binding DataContext.SelectCardCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}}" 
                           CommandParameter="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/>
</i:EventTrigger>

or using ElementName

<i:EventTrigger EventName="Click">
    <i:InvokeCommandAction Command="{Binding DataContext.SelectCardCommand, ElementName=LayoutRoot}" 
                           CommandParameter="{Binding Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Rectangle}}"/>
</i:EventTrigger>

EDIT

after executing the code I realized the reason, as rectangle do not have any event named Click so it does not bind, however you can bind to UIElement.MouseDown

alternatively I came up with a different approach to solve your issue.

I modify the template a bit to use Button and templated the button as needed and also changed the ItemsPanelTemplate so it look more like a memory game

    <ItemsControl ItemsSource="{Binding GameBoard.CardList}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Command="{Binding DataContext.SelectCardCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}}"
                        CommandParameter="{Binding}">
                    <Button.Template>
                        <ControlTemplate>
                            <Rectangle Fill="{Binding Converter={StaticResource ColorConverter}}"
                                       Height="100"
                                       Width="100"
                                       Margin="10,10,0,0"
                                       Stroke="Black">
                            </Rectangle>
                        </ControlTemplate>
                    </Button.Template>
                </Button>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

the command

    #region SelectCardCommand

    public RelayCommand<Card> SelectCardCommand { get; private set; }

    #endregion

    public MainViewModel()
    {
        SelectCardCommand = new RelayCommand<Card>((s) => DoSelectCardCommand(s));
        GameBoard = new Board();
        this.StartGame();
    }

    private void DoSelectCardCommand(Card card)
    {
        if (card != null)
            card.Upside = true;
    }

this will help you remove int.Parse(card.Substring(4,2)); and other string manipulations too