Search code examples
c#wpfmvvmitemscontroleventtrigger

Triggering an event from ItemsControl (WPF MVVM)


I am using WPF MVVM design pattern. I need to raise a PreviewKeyDown event from a textbox that was created using an ItemsControl. I am able to add items to the collection SourceCollection, but unable to trigger the PreviewKeyDown event using interaction triggers. Any ideas on what I might be missing in the xaml is appreciated :) Here's my code:

MainWindow.xaml

    <Grid>
        <ItemsControl ItemsSource="{Binding SourceCollection}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding CollectionText}" Foreground="{Binding Path=ForegroundColor}"
                             FontSize="16" FontWeight="ExtraBold" FontFamily="Courier New">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="PreviewKeyDown">
                                <i:InvokeCommandAction Command="{Binding KeyDownAction}"></i:InvokeCommandAction>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </TextBox>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>

MainWindowViewModel.cs

public class MainWindowViewModel
{
    MainWindowModel model = new MainWindowModel();

    private ObservableCollection<MainWindowModel> _SourceCollection;
    public ObservableCollection<MainWindowModel> SourceCollection
    {
        get { return _SourceCollection; }
        set { _SourceCollection = value; }
    }

    public MainWindowViewModel()
    {
        SourceCollection = new ObservableCollection<MainWindowModel>();

        for (int i = 0; i < 4; i++)
        {
            model = new MainWindowModel();
            model.CollectionText = "This is line " + i;
            if (i % 2 == 0)
            { model.ForegroundColor = Brushes.Blue; }
            else
            { model.ForegroundColor = Brushes.Green; }
            SourceCollection.Add(model);
        }
    }

    public RelayCommand<KeyEventArgs> KeyDownAction
    {
        get { return new RelayCommand<KeyEventArgs>(KeyDownMethod); }
    }

    private void KeyDownMethod(KeyEventArgs e)
    {
        //some code here 
    }
}

Solution

  • the "Binding" for your Command in the "InvokeCommandAction" is incorrect. It is NOT on an individual collection item, but at the ViewModel level. Change it to:

    <i:InvokeCommandAction 
      Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, 
      Path=DataContext.KeyDownAction}">
    </i:InvokeCommandAction>
    

    This way you're pointing to the command defined in the ViewModel.