Dom Sinclair
Dom Sinclair

Reputation: 2528

Interaction Trigger appears not to be firing

I have a user control and I've been doing some experimentation with handling events of various controls in the underlying view model. In many cases I have found that using some basic xaml like the bit below works.

<i:Interaction.Triggers>
            <i:EventTrigger EventName="Event to be handled">
                <i:InvokeCommandAction Command="{Binding Path= I Command handling event}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>

However I have been trying this with a text box defined in my xaml like so:

 <TextBox x:Name="TxtInvNumber" Margin="5" Grid.Column="1" Width="80" Text="{Binding Path=InvoiceNumber}" >
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="TextChanged">
                <i:InvokeCommandAction Command="{Binding Path=InvoiceNumberChangedCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>

When done like this and with a breakpoint set on the InvoiceNumberChangedCommand nothing happens, yet if I put a simple message box in the TextChanged handler in the code behind the view it gets fired every time.

Can anyone explain if this is something particular to text boxes or is it that using interactions to handle events in this way doesn't always work?

Incidentally I had wondered if this might have had something to do with the fact that the text box text property is bound to an underlying property that implements propertychanged so I tried it with the LostFocus event as well and still the same result.

Thanks

Upvotes: 1

Views: 6448

Answers (2)

icernos
icernos

Reputation: 403

Requirements for Interaction.Triggers to work:

  1. Add reference to 'System.Windows.Interactivity'
    a) Here's one way. https://stackoverflow.com/a/52110697/6010880
  2. Add this attribute to XAML.
    b) xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

    enter image description here

    Here's the complete solution that you can try from a new project. Just copy and paste the 4 files below:

    1. MainWindow.xaml
    2. MainWindow.xaml.cs
    3. MainViewModel
    4. DelegateCommand.cs

    XAML



Code Behind (MainWindow.xaml.cs)

using System.Windows;

namespace WpfApp1
{
   public partial class MainWindow : Window
   {
       private readonly MainViewModel _main = new MainViewModel();

    public MainWindow()
    {
        InitializeComponent();

        DataContext = _main;  //<-- It does not need to be before InitializeComponent()
    }
}

}


MainViewModel.cs

using System.Windows.Input;

namespace WpfApp1 { public class MainViewModel { protected ICommand _windowsLoadedVm;

    public ICommand WindowsLoadedVm
    {
        get
        {
            if (_windowsLoadedVm == null)
            {
                _windowsLoadedVm = new DelegateCommand(WindowsLoadedHandler);
            }
            return _windowsLoadedVm;
        }
    }

    public void WindowsLoadedHandler(object parameter)
    {
        //Do your thang!
    }
}

}


DelegateCommand.cs

using System;

using System.Windows.Input;

namespace WpfApp1
{
   public class DelegateCommand : ICommand
   {
     private readonly Predicate<object> _canExecute;
     private readonly Action<object> _execute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<object> execute)
                   : this(execute, null)
    {
    }

    public DelegateCommand(Action<object> execute,
                   Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecute == null)
        {
            return true;
        }

        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

}

Upvotes: 1

Michal Ciechan
Michal Ciechan

Reputation: 13898

It works for me... Few possible things to check:

  1. System.Windows.Interactivity are you using?
  2. Are you sure your command is raising a notify property changed, or being set before InitializeComponent()?

View.cs

public partial class InteractionTriggerNotFiring : Window
{
    public InteractionTriggerNotFiring()
    {
        DataContext = new SO29051551VM();
        InitializeComponent();

    }
}

View.xaml

<Window x:Class="WpfApplication1.InteractionTriggerNotFiring"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        Title="InteractionTriggerNotFiring" Height="300" Width="300">
    <Grid>
        <TextBox x:Name="TxtInvNumber" Margin="5" Grid.Column="1" Width="80" Text="{Binding Path=InvoiceNumber}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="TextChanged">
                    <i:InvokeCommandAction Command="{Binding Path=InvoiceNumberChangedCommand}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TextBox>
    </Grid>
</Window>

View Model

public class SO29051551VM : ViewModelBase
{
    private RelayCommand _invoiceNumberChangedCommand;

    public SO29051551VM()
    {
        InvoiceNumberChangedCommand = new RelayCommand(() =>
        {
            Console.WriteLine("TEst");
        });
    }
    public RelayCommand InvoiceNumberChangedCommand
    {
        get { return _invoiceNumberChangedCommand; }
        set
        {
            if (_invoiceNumberChangedCommand == value) return;
            _invoiceNumberChangedCommand = value;
            RaisePropertyChanged(() => InvoiceNumberChangedCommand);
        }
    }
}

Upvotes: 0

Related Questions