What I have:
I have a combobox. Here is its LostFocus using Command in MVVM style:
<ComboBox .............>
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding DataContext.OrderIdLostFocusCommand, UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
And in the ViewModel:
//Constructor
public DispatchViewModel(IEventAggregator _eventAggregator)
{
eventAggregator = _eventAggregator;
//Some Code
OrderIdLostFocusCommand = new RelayCommand(Execute_OrderId_LostFocus);
}
public RelayCommand OrderIdLostFocusCommand { get; set; }
private void Execute_OrderId_LostFocus(object obj)
{
//Some Calculations
eventAggregator.GetEvent<MoveFocusToDatePickerEvent>().Publish(true);
}
In the Code-Behind:
//Constructor
public DispatchView(DispatchViewModel _viewModel, IEventAggregator _eventAggregator)
{
InitializeComponent();
this.DataContext = _viewModel;
_eventAggregator.GetEvent<MoveFocusToDatePickerEvent>().Subscribe(MoveFocusToDateOfDispatch);
}
private void MoveFocusToDateOfDispatch(bool obj)
{
this.Dispatcher.BeginInvoke((Action)delegate { dpInvoice.Focus(); }, DispatcherPriority.Render);
}
Problem:
When Combobox is focused and if I try to open it's DropDown then its lostfocus event fires and so focus moves to DataPicker.
What I want:
Instead I want to fire LostFocus event only when IsKeyboardFocusWithin property of ComboBox is false.
Just use an interactions DataTrigger on IsKeyboardFocusWithin being false. It's in the http://schemas.microsoft.com/expression/2010/interactions namespace.
<i:Interaction.Triggers>
<ii:DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ComboBox},
Path=IsKeyboardFocusWithin}"
Value="false">
<i:InvokeCommandAction .../>
</ii:DataTrigger>
</i:Interaction.Triggers>
Related
So I use the Autosuggestionbox of the ModernWPF Toolkit and was trying to get to handle the "QuerySubmitted" event from it via the MVVM way. Here's what I have
<ui:AutoSuggestBox x:Name="TextBox"
Text="{Binding TextBoxID, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ItemsSource="{Binding Path= TextBoxCollection}"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="QuerySubmitted" >
<i:InvokeCommandAction Command ="{Binding QuerySubmit}" CommandParameter="{Binding ElementName=TextBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ui:AutoSuggestBox>
Heres my ViewModel
public ICommand textBox
public ICommand QuerySubmit
{
get
{
if(textBox== null)
{
///Do some stuff when event fires
}
return textBox;
}
}
and for the namespace of i its
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
But it doesn't seem to work so far. Any guesses on why and how to fix it?
To add, I tried switching it to a different event (MouseDoubleClick) and it works, so I think it's about the event of the querysubmit itself.
How do i trigger the SourceUpdate of my wpf listview?
This is my xaml
<ListView DataContext="{StaticResource vmInstance}" SelectedItem="{Binding selectedItem}" BorderBrush="Beige" BorderThickness="1" ItemsSource="{Binding lstExternal}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged" >
<cmd:EventToCommand Command="{Binding Path=ItemChanged}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="SourceUpdated">
<cmd:EventToCommand Command="{Binding Path=SourceUpdated}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.View >
</ListView.View>
</ListView>
ViewModel:
public static RelayCommand SourceUpdated { get; set; }
//on initialize
SourceUpdated = new RelayCommand(SourceUpdateEvent);
public void SourceUpdateEvent()
{
Console.WriteLine("Updated");
}
Why does SourceUpdateEvent doesn't run?
Am I using the wrong event?
Thank you
want to execute a method when the itemsource of the listview is changed or updated
Then bind the ItemsSource property of the ListView to a source property of your view model
<ListView ItemsSource="{Binding YourCollection}" ...>
...and invoke your command in the setter of this source property:
private ObservableCollection<YourType> _sourceCollection;
public ObservableCollection<YourType> SourceCollection
{
get { return _sourceCollection; }
set
{
_sourceCollection = value;
RaisePropertyChanged();
SourceUpdated.Execute(null);
}
}
This is the (only) correct way to solve this using the MVVM pattern.
I would like to refactor my code a bit with Propertychanged.Fody as shown on this page http://www.mutzl.com/tag/mvvm-light/
Normal code:
private string _platformSelectedItem;
public string PlatformSelectedItem
{
get { return _platformSelectedItem; }
set
{
if (_platformSelectedItem == value) return;
_platformSelectedItem = value;
// Perform any pre-notification process here.
GetData();
RaisePropertyChanged();
}
}
to
public string PlatformSelectedItem {get; private set}
The property is bounded to a Comboxbox and the values for the Combobox are dynamic based on another combobox, therefore I have my Method GetData().
<ComboBox ItemsSource="{Binding Platforms}" SelectedItem="{Binding PlatformSelectedItem, Mode=TwoWay}" Grid.Column="1" Grid.Row="2" Height="20" Grid.ColumnSpan="2" Margin="0,3,15.667,3"/>
If I refactor my code to autoproperties the method must be executed by click / open of the combobox.
Should I use a eventtrigger with command our is a more simpler way possible?
Based on the thread can we use <i:Interaction.Triggers> in WPF MVVM (not in Silverlight)
My final solution looks:
ViewModel:
Properties area:
public RelayCommand SelectionChangedCommand { get; private set; }
Constructor:
SelectionChangedCommand = new RelayCommand(Update);
Method area:
private void Update()
{
GetData();
}
In my UI then:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<ComboBox ItemsSource="{Binding Platforms}" SelectedItem="{Binding PlatformSelectedItem, Mode=TwoWay}" Grid.Column="1" Grid.Row="2" Height="20" Grid.ColumnSpan="2" Margin="0,3,15.667,3">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectionChangedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
I am trying to bind a click on button event in WPF to a command defined in a View Model, here is how I am doing that for now :
In the xaml code :
<Grid>
<Button Content="Module A" Background="Green" FontWeight="Bold">
<i:Interaction.Triggers>
<i:EventTrigger EventName="click">
<i:InvokeCommandAction Command="{Binding ChargeModuleDCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
and in the ViewModel class :
class ModuleAViewModel
{
public DelegateCommand<object> ChargeModuleDCommand { get; set; }
public ModuleAViewModel()
{
ChargeModuleDCommand = new DelegateCommand<object>(LaunchDModule);
}
private void LaunchDModule(object parm)
{
Console.WriteLine("I am in the function");
}
}
but it does not work. I've tried to do it as specified in this question : How to trigger ViewModel command for a specific button events
but it does not work either.
Is there any way that I can make it work ?
<Button
Command="{Binding ChargeModuleDCommand}"
Content="Module A"
Background="Green"
FontWeight="Bold"
/>
If ModuleAViewModel is the Button's DataContext, that should work.
I have a Textbox and for that textbox I have attached a keydown event. Everything is working fine but I just noticed that when i'm pressing the 'Backspace' and 'Delete' Key, the binding command is not being called.
My View xaml file :-
<TextBox x:Name="textBox" Width="500" Text="{Binding TextBoxText, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{BindingPath=TextBoxKeyDownEvent}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
My ViewModel cs file :-
//TextBox Key Down Event Handler
private DelegateCommand _textBoxKeyDownEvent;
public ICommand TextBoxKeyDownEvent
{
get
{
if (_textBoxKeyDownEvent == null)
{
_textBoxKeyDownEvent = new DelegateCommand(TextBoxKeyDownEventHandler);
}
return _textBoxKeyDownEvent;
}
set { }
}
Can somebody give me some suggestion
EDIT:
You have to use PreviewKeyDown the it works. KeyDown is not fired on Space and Delete. If you ignore MVVM and put the handler of KeyDown in codebehind it will also fail.
How about binding the Text-Property to a string in you viewmodel?
I build a fast, simple example of my idea.
Result
Text from the TextBox on the left side is simply populated to the Textblock on the right side.
View
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding TextBoxValue, UpdateSourceTrigger=PropertyChanged}" Width="250"/>
<StackPanel Orientation="Horizontal">
<TextBlock>"</TextBlock>
<TextBlock Text="{Binding TextBoxValue, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock>"</TextBlock>
</StackPanel>
</StackPanel>
</Window>
ViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
private string textBoxValue;
public string TextBoxValue
{
get { return textBoxValue; }
set
{
textBoxValue = value;
OnTextBoxValueChanged();
RaisePropertyChanged();
}
}
void OnTextBoxValueChanged()
{
// you logic here, if needed.
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
you most use PreviewKeyDown event.
Like this:
<EventSetter Event="PreviewKeyDown" Handler="TextBox_PreviewKeyDown"/>
Edit: You are correct - the default behavior is not executed. You should use ec8ors solution, which is much better anyway:
<TextBox x:Name="textBox" Width="500" Text="{Binding TextBoxText, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewKeyDown">
<i:InvokeCommandAction Command="{Binding TextBoxKeyDownEvent, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
Original:
You can use InputBindings to call your command when "special" keys have been pressed:
<TextBox x:Name="textBox" Width="500" Text="{Binding TextBoxText, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{BindingPath=TextBoxKeyDownEvent}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBox.InputBindings>
<KeyBinding Command="{Binding TextBoxKeyDownEvent}" Key="Delete" />
<KeyBinding Command="{Binding TextBoxKeyDownEvent}" Key="Back" />
</TextBox.InputBindings>
</TextBox>