Do you know is it possible to get element on MouseOver from ListView in WPF using XAML?
I would like to bind mouse over element to command parameter.
What should I type in Path ?
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding SetOnMousePlayerCommand}"
CommandParameter="{Binding ElementName=leftPlayersListViewGame, Path=XXX}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Probably I have to do it in another way ? Could you tell my how ?
if you are looking to access the Event Args here how you should proceed:
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<command:EventToCommand Command="{Binding Mode=OneWay,Path=MouseEnterCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
private RelayCommand<MouseEventArgs> _mouseEnterCommand;
public RelayCommand<MouseEventArgs> MouseEnterCommand
{
get
{
return _mouseEnterCommand
?? (_mouseEnterCommand= new RelayCommand<MouseEventArgs>(
(s) =>
{
//your logic
}));
}
}
but if you are looking for the sender of the Event, so here is your answer Pal :
Passing event args and sender to the RelayCommand
Related
So this is what i have try:
<TextBox Name="TextBoxLatter">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<i:InvokeCommandAction Command="{Binding Path=TextBoxKeyDownCommand}"
CommandParameter="{Binding ElementName=TextBoxLatter, Path=Text}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
And inside my Execute method my parameter is null:
public void Execute(object parameter)
{
}
Your current approach should work if you handle the KeyUp event instead of KeyDown.
But you should bind the Text property of TextBoxLatter to a string source property of the view model. You could then access it directly in the Execute method of the command:
public void Execute(object _)
{
string text = this.YourProperty;
//...
}
XAML:
<TextBox Name="TextBoxLatter" Text="{Binding YourProperty, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<i:InvokeCommandAction Command="{Binding Path=TextBoxKeyDownCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
Say I have a Telerik RadGridView, outside there is a button. When the mouse is clicking row in the RadGridView, the button is enabled. If the mouse moves outside the RadGridView, then the button is disabled.
My code is
rgv_LostFocus(object sender, eventArgs e)
{
// do something
MyViewModel.IsButtonEnabled = false;
}
However I don't want to use code behind. Maybe using behavior?
You could use an interaction trigger from System.Windows.Interactivity and a ChangedPropertyAction from Microsoft.Expression.Interactions.dll:
<telerik:RadGridView xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<ei:ChangePropertyAction TargetObject="{Binding}" TargetName="IsButtonEnabled" Value="false" />
</i:EventTrigger>
</i:Interaction.Triggers>
...
</telerik:RadGridView>
Please refer to this blog post for information about how to handle events in a MVVM application.
Per #mm8 hint.
<telerik:RadGridView xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding LostFocusCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</telerik:RadGridView>
Then in ViewModel,
public DelegateCommand LostFocusCommand = new DelegateCommand(RadGridViewLostFocus);
In the method 'RadGridViewLostFocus' set the bool property as false;
private void RadGridViewLostFocus()
{
IsButtonEnabled = false;
}
<TreeView x:Name="TestTree"
ItemsSource="{Binding Children}"
ItemTemplateSelector="{StaticResource TemplateSelector}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="TreeViewItem.Seleted">
<i:InvokeCommandAction
Command="{Binding SelectedCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
As above codes mentioned, I wanna get the selected treeviewitem data from the view, while the binding event TreeViewItem.Seleted which is an attached event(member event is okay) cannot be received in the viewmodel. How to binding an attached event to viewmodel?
then, you won't get TreeViewItem event in the TreeView ? you need a custom item template. I do it like this on a datagrid with MVVMLight (but no item)
</DataGrid.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick" >
<command:EventToCommand Command="{Binding Path=OpenEquipementCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="SelectionChanged">
<command:EventToCommand Command="{Binding Path=SelectionChangedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
so i think you must do
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged" >
<command:EventToCommand Command="{Binding Path=SelectionChangedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
Why don't just use plain old eventhandler?
<TreeView x:Name="TreeView1" SelectedItemChanged="TreeView_SelectedItemChanged" />
public partial class MainWindow : Window
{
MainWindowViewModel ViewModel => (MainWindowViewModel) DataContext;
private void TreeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var element = (FrameworkElement)sender;
var item = element.DataContext;
ViewModel.SelectionChangedCommand.Invoke(item);
//alternativelly:
ViewModel.SelectedItem = TreeView1.SelectedItem;
}
}
Just because WPF support binding, it does not mean you have to use it everywhere even if it's very complicated. The code I've written is not violation of MVVM.
If you have a good reason to avoid code behind, you may implement this eventhandler in a custom behavior implemented as attached property, so it would look like this:
<TreeView local:TreeViewBehavior.SelectionChangedCommand="{Binding SelectionChangedCommand}" />
I have a ToggleButton in my C# WPF application where I would like to bind one Command to the Checked event and one Command to the Unchecked event.
What I have currently is the following:
<ToggleButton Name="btnOpenPort" Style="{StaticResource myOnOffBtnStyle}" Content="Open Port"
Checked="btnOpenPort_Checked" Unchecked="btnOpenPort_Unchecked"
IsChecked="{Binding Path=PortViewModel.PortIsOpen, Mode=OneWay}"
Canvas.Left="75" Canvas.Top="80" Height="25" Width="100"/>
But this is not what I aim to do. Because in this case, I would have to set properties in the code behind for the Checked and Unchecked event.
Instead, I would like to call a Command (ICommand) in my ViewModel once the Checked or Unchecked event gets fired so that I don't need any code-behind for my toggle button.
Is there a way to bind a command directly for these two events in XAML?
Similar to the command property of the "standard" button control in WPF?
EDIT
This is how it works with regards to #har07 hint:
1: Added references if you dont have it yet:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
2: Implemented Interaction.Triggers for Checked and Unchecked events:
<ToggleButton
Name="btnOpenPort" Style="{StaticResource myOnOffBtnStyle}" Content="Open Port"
IsChecked="{Binding Path=PortViewModel.PortIsOpen, Mode=OneWay}"
Canvas.Left="75" Canvas.Top="80" Height="25" Width="100">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding Path=PortViewModel.OpenPort}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding Path=PortViewModel.ClosePort}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ToggleButton>
With this solution, I don't have to change a single line of code in my ViewModel or my code behind.
I can just call my ICommand as I would do it with a standard button following MVVM pattern.
you may not be able to bind two commands for each checked and unchecked directly however you can still bind a command, which will be invoked for both. you also have option for attached behaviors if you need different command for both events.
<ToggleButton Command="{Binding MyCommand}"/>
in the vm
public ICommand MyCommand { get; private set; }
you will need to initialize it accordingly
and to determine the current state you may have a condition on the bonded property PortIsOpen
void Execute(object state)
{
if(PortIsOpen)
{
//checked
}
else
{
//unchecked
}
}
or perhaps you may pass it as a parameter too
eg
<ToggleButton Command="{Binding MyCommand}"
CommandParameter="{Binding IsChecked,RelativeSource={RelativeSource Self}}"/>
and use it as
void Execute(object state)
{
if((bool)state)
{
//checked
}
else
{
//unchecked
}
}
Maybe we can use EventTriggers
<ToggleButton>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding Path=CheckedCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding Path=UncheckedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ToggleButton>
to use Triggers we have to reference System.Windows.Interactivity
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
You can put the logic to handle checked/unchecked event in the setter of PortIsOpen property :
private bool _portIsOpen;
public bool PortIsOpen
{
get { return _portIsOpen; }
set
{
if(value) HandleCheckedEvent();
else HandleUnCheckedEvent();
....
}
}
Or you can use Ineraction.Triggers extension to bind event to commmand :
WPF Binding UI events to commands in ViewModel
<ToggleButton Name="btnOpenPort" Style="{StaticResource myOnOffBtnStyle}" Content="Open Port"
Checked="{Binding ICommand}" Unchecked="{Binding ICommand}"
IsChecked="{Binding Path=PortViewModel.PortIsOpen, Mode=OneWay}"
Canvas.Left="75" Canvas.Top="80" Height="25" Width="100"/>
Replace ICommand with your ICommand property name.
MVVM light has been a pleasure to learn, but here I am stuck. The problem is event firing.
In the code below, one button the works and fires events. The other button doesnt. No binding errors are reported in the output. Is there anything obvious I am missing?
<Grid x:Name="LayoutRoot">...
<StackPanel>
<Button Content="THIS BUTTON WORKS">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Command:EventToCommand Command="{Binding DataContext.HandleAddQuestionActionCommand, ElementName=LayoutRoot, Mode=OneWay}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<sdk1:DataGrid ItemsSource="{Binding QuestionActions}" AutoGenerateColumns="False" >
<sdk1:DataGrid.Columns>
<sdk1:DataGridTextColumn Binding="{Binding Answer.Name}" Header="Answer"/>
<sdk1:DataGridTemplateColumn Header="Edit">
<sdk1:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="THIS BUTTON DONT WORK" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Command:EventToCommand Command="{Binding DataContext.HandleEditQuestionActionCommand, ElementName=LayoutRoot, Mode=OneWay}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</sdk1:DataGridTemplateColumn.CellTemplate>
</sdk1:DataGridTemplateColumn>
</sdk1:DataGrid.Columns>
</sdk1:DataGrid>
</StackPanel>
ViewModel code:
public RelayCommand<RoutedEventArgs> HandleAddQuestionActionCommand {
get; private set;
}
public RelayCommand<RoutedEventArgs> HandleEditQuestionActionCommand {
get; private set;
}
HandleAddQuestionActionCommand = new RelayCommand<RoutedEventArgs>(e =>{...});
HandleEditQuestionActionCommand = new RelayCommand<RoutedEventArgs>(e =>{...});
Your data context is lost in the DataGrid DataGridTemplateColumn since the DataGrid.Columns isn't a dependency property. Because of this, you can't use element-to-element data binding from within your DataGridTemplateColumn.
However, this is easily fixed thanks to MVVM Light Toolkit's ViewModelLocator.
I don't know what your ViewModel is called, but assuming it is MainViewModel you can change your button binding to this:
<sdk1:DataGridTemplateColumn Header="Edit">
<sdk1:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="THIS BUTTON WILL WORK NOW ;-)" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Command:EventToCommand Command="{Binding Source={StaticResource Locator},
Path=MainViewModel.HandleEditQuestionActionCommand}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</sdk1:DataGridTemplateColumn.CellTemplate>
</sdk1:DataGridTemplateColumn>
The button inside the DataGrid has a DataContext of QuestActions since the Binding is based on the the DataGrid's ItemSource Property. That being the case, you'll need to find the DataContext of the DataGrid itself (or the UserControl or whatever parent that has the Command in it's DataContext) to get to your Command:
<Command:EventToCommand
Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type sdk1:DataGrid}},
Path=DataContext.ViewSchemaCommand, Mode=OneWay}"
PassEventArgsToCommand="True" />
This solution only works for static view models. check out Dan Whalin's page out for an alternative answer. http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx
You can create a resource like so (don't forget your reference):
<UserControl.Resources>
<controls:DataContextProxy x:Key="DataContextProxy" />
</UserControl.Resources>
or
<sdk:Page.Resources>
<controls:DataContextProxy x:Key="DataContextProxy"/>
</sdk:Page.Resources>
Use in control like so:
<sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Content">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding Source={StaticResource DataContextProxy}, Path=DataSource.MyCommand}"
CommandParameter="{Binding Path=SomeValue}"
PassEventArgsToCommand="False">
</cmd:EventToCommand>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
ViewModel
Define RelayCommand:
public RelayCommand<object> MyCommand { get; set; }
Set RelayCommand in Constructor:
MyCommand = new RelayCommand<object>((e) =>
{
if (e != null && e is int)
{
int varName = int.Parse(e.ToString());
//DoSomething...
}
});