Reputation: 2528
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
Reputation: 403
Requirements for Interaction.Triggers to work:
Add this attribute to XAML.
b) xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
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
Reputation: 13898
It works for me... Few possible things to check:
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