0

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 
    }
}
  • 1
    I believe the reason why you are not able to capture the event is because the DataContext of your TextBox is actually the ItemsSource of your ItemsControl. You need to bind your command with RelativeSource https://stackoverflow.com/questions/1127933/wpf-databinding-how-do-i-access-the-parent-data-context – Stojdza Mar 15 '18 at 19:03
  • @Stojdza yes it makes sense now. Thanks :) – Vandana Chandola Mar 15 '18 at 19:27

2 Answers2

1

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.

arlvin
  • 379
  • 1
  • 4
  • 11
0

You should have below ICommand definitions in your WindowModel rather than MainWindowViewModel.

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

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

Because datacontext for item template of your itemcontrol is item and not main view model.

rahulaga-msft
  • 3,964
  • 6
  • 26
  • 44