Using an EventTriggers in a DataGridTemplateColumn - silverlight

I am using Silverlight 5 and in a view I have a Button that, when clicked, loads a particular state. This is done using an EventTrigger and the GoToStateAction markup like so:
<Button x:Name="..." Content="...">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:GoToStateAction StateName="MyState"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
The above works swimmingly, but if I move the Button into a DataGridTemplateColumn it no longer works. Specifically, the app compiles without error and the DataGrid shows the button in a column, but when I click the button the state is not transitioned to.
<data:DataGrid ...>
<data:DataGrid.Columns>
<data:DataGridTemplateColumn>
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="..." Content="...">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:GoToStateAction StateName="MyState"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
Is it not possible to have EventTriggers in a DataGridTemplateColumn? Or do I need to declare them using alternate syntax?
Thanks

The GoToStateAction reference states that, if no target is specified, it will walk up the visual tree and apply the state change on the first element it finds that defines states. In your second case, I believe that some elements of the DataGrid visual tree (cells, rows, etc) may be taken in account before your usercontrol, thus the behavior you've seen.
Since you are using Silverlight 5, you can try to set the TargetObject property of the action to your desired control, using a binding with a relative source looking of a ancestor of the type of UserControl.
<ei:GoToStateAction StateName="MyState" TargetObject="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}"/>

Related

Event trigger is not working inside ItemControl

I have a Item control which fills by a list, and list is collection of two parameters 'Time' and 'Description'. For it, i am using a HyperLinkButton for time and a Label for description.
What i want is that, i want to create click event using EventTrigger of hyperLink button in Main viewModel. My code is:
<ItemsControl
x:Name="transcriptionTextControl"
ItemsSource="{Binding MyCollectionOfTranscription, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<HyperlinkButton Content="{Binding Time}">
<ToolTipService.ToolTip>
<ToolTip Content="Time"/>
</ToolTipService.ToolTip>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction
Command="{Binding HyperLinkButtonCommand}"
CommandParameter="{Binding
ElementName=transcriptionTextControl }" />
</i:EventTrigger>
</i:Interaction.Triggers>
</HyperlinkButton>
<sdk:Label Content="{Binding Description}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
When i build project, it doesn't give error but ICommand for hyperLink, shows warning as 'Cannot resolve symbol HyperLinkButtonCommand', while this event trigger is working fine outside this .
Not getting, what is actual problem behind it, plz give your valuable suggestion...
First off,
<i:InvokeCommandAction
Command="{Binding HyperLinkButtonCommand}"
CommandParameter="{Binding
ElementName=transcriptionTextControl }" />
The Binding is trying to locate a property called HyperLinkButtonCommand on the instance of the type that is contained within MyCollectionOfTranscription (you don't need to bind to this two-way).
(Side note, sending an ItemsControl into your Command is not MVVM.)
The ItemsControl iterates through each element in this collection, creates a copy of the template defined in ItemsControl.ItemTemplate, and sets the BindingContext equal to this element (I assume its a Transcript). You can tell this from the warnings you get from the binding failing to find your HyperLinkButtonCommand if you crank up databinding debug settings.
Assuming
HyperLinkButtonCommand is a command defined in your ViewModel, and
The root of this xaml is a Window (could be a UserControl, but am assuming here)
Your ViewModel is the DataContext of the Window
you can change the binding to the following and it should work (or you should get a clue from it)
<i:InvokeCommandAction
Command="{Binding HyperLinkButtonCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
CommandParameter="{Binding
ElementName=transcriptionTextControl }" />
I prefer just to give my root an x:Name of "root" and use "ElementName=root" in cases like this.

Wpf checkbox trigger

Trying to bind the click or checked event on a WPF chekbox to a command in my viewmodel, but im unsure on the technique and the event names, can anyone point me in the right direction?
For now the code compiles but the the trigger does not call the FooCommand
<CheckBox IsChecked="{Binding PartData.ReportIncluded, Mode=TwoWay}"
VerticalAlignment="Center">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown" >
<i:InvokeCommandAction Command="{Binding FooCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
Looks like you're missing the "On" prefix of your event, i.e. OnMouseLeftButtonDown or OnPreviewMouseLeftButtonDown

Handling listbox item selected

Seems like this would be a common problem...
I'm using MVVM Light
I have a listbox defined in my xaml
<ListBox ItemsSource="{Binding Events}" SelectedItem="{Binding SelectedEvent, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<cmd:EventToCommand Command="{Binding EventPageCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Padding="0,0,0,22">
<StackPanel>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Preview}" TextWrapping="Wrap"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This works all fine and dandy, except the user is able to click below this list and the event is still fired.
I can modify it to use SelectionChanged such as:
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding EventPageCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
But then if I use the back button, I cannot select the same item twice since the selection hasn't actually changed. I could probably go into my codebehind and set the selected index = -1 on page load, but this seems like quite a hack, and I use list boxes in quite a few places and I would hate to have to remember to do this hack everywhere.
Any ideas?
edit
I added background color to my listbox and my listbox items and while my listbox items only take up what space the text occupies, the listbox takes up the entire screen, extending below the last listbox item. Perhaps one way would be to shore up this extra space.
update
what seems to work best so far is to set the VerticalAlignmnet="Top" on the listbox (this shores up the extra space on the bottom, not sure why, but then scrolling ends at the bottom of the list and not the bottom of the screen). I then disabled the scrolling on the listbox itself ScrollViewer.VerticalScrollBarVisibility="Disabled" and wrapped the whole thing in a <ScrollViewer>
Currently you are looking for the Tap event on the whole of the list box, not a individual item.
This is how I typically I use interaction triggers:
<DataTemplate DataType="{x:Type ViewModel:DataItem}" x:Key="ItemTemplate">
<ContentControl>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding Tap}"/>
</i:EventTrigger>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction
Command="{Binding RelativeSource={RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBox}},
Path=DataContext.KeyUpCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBox Text="{Binding Name}"/>
</ContentControl>
</DataTemplate>
In this example the Tap event binds to a command on the DataContext (a data item) of an ItemsControl, whereas the KeyUp event binds to a command on the parent DataContext of the ListBox.
If all you want is to get an event when the user taps an item, why don't you use the trigger code you have on the Border element of the template?
You probably will have to use the Source property to bind the command to the ViewModel, but that can also be easely achieved (will just depend on how you are setting the Page DataContext right now)

Using buttons in DataTemplate for DataGrid for Action

Ok so here's what I got, as example.
<sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<HyperlinkButton Content="Delete" Visibility="{Binding Priority, Converter={StaticResource FDPriorityToVisibilityConverter}}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="DeleteRule">
<cal:Parameter Value="{Binding Id}"/>
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</HyperlinkButton>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
What I want to do is replace the HyperlinkButton control with a Button (Essentially just deleting "Hyperlink" from the tag ), but it doesnt respect the eventtrigger when I do that. So when clicked it just doesnt do anything. I figured I could maybe solve this with replacing cal:ActionMessage with EventToCommand but I must not be implementing correctly.
Short version of question, can someone shed some light on how I can get the functionality the existing HyperlinkButton accomplishes, but with a button control so I can give it an icon instead of just text that says Delete? Thanks for any insight!
For answer read my comment made, I believe this issue is circumstantial and a workaround was deliberated.

WPF Interaction triggers in a Style to invoke commands on View Model [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to add a Blend Behavior in a Style Setter
when I use an interaction trigger in a style, I am getting the following error, 'triggers is not attachable element of type style'. Any explanation what this error actually means and how to solve it.
For reference take a look at MVVM Light toolkit's EventToCommand example.
In this particular case, I am using Timeline control from Infragistics which represents events as EventTitle and when the EventTitle is clicked, I would like to raise the command (Note that Timeline control doesn't define any event like EventTitleClicked). Currently I am able to achieve the functionality by using events and calling my ViewModel method from the code behind, instead I would like to invoke the command directly from xaml.
<Style x:Key="EventTitleTopStyle" TargetType="igTl:EventTitle">
<!-- The following is not working -->
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<!--<cmd:EventToCommand Command="{Binding MyCommand}" />-->
</i:EventTrigger>
</i:Interaction.Triggers>
<!-- Using event setter instead to achieve the same -->
<EventSetter Event="MouseLeftButtonDown" Handler="TopTitleMouseLeftButtonDown" />
....
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="MouseDoubleClick">
<behaviours:ExecuteCommandAction Command="{Binding Path=DataContext.YourCommand, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}}}"
CommandParameter="{Binding }"/>
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
<TextBox x:Name="EditableControlTextBox" Loaded="RoomTextBox_Loaded">
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="LostFocus">
<!--<cmd:EventToCommand Command="{Binding MyCommand}" />-->
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
</TextBox>

Resources