I wrote my own Behavior to handle a swipe gesture and put it to the ItemTemplate of a ListView. If a swipe is completed, I raise an event for LeftSwipe or RightSwipe. This event should be handled by my ViewModel.
I use the syntax of Caliburn.Micro to attach handler to an event: cm:Message.Attach="[Event LeftSwipe] = [LeftSwipe($source, $eventArgs)"
.
This is my Behavior:
public class SwipeInteractionBehavior : DependencyObject, IBehavior
{
public DependencyObject AssociatedObject { get; private set; }
public void Attach(DependencyObject associatedObject)
{
// ...
}
public void Detach()
{
// ...
}
public event EventHandler LeftSwipe;
public event EventHandler RightSwipe;
// ...
// ...
private void OnLeftSwipe(FrameworkElement element)
{
// ...
if (LeftSwipe != null)
{
LeftSwipe(this, EventArgs.Empty);
}
}
private void OnRightSwipe(FrameworkElement element)
{
// ...
if (RightSwipe != null)
{
RightSwipe(this, EventArgs.Empty);
}
}
}
This is how I use this Behavior inside of ListViews ItemTemplate:
<ListView x:Name="Links" IsItemClickEnabled="True" SelectionMode="None" cm:Message.Attach="[Event ItemClick] = [Click($source, $eventArgs)]">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid>
<Border x:Name="todoItem" Loaded="Border_Loaded" Background="White">
<i:Interaction.Behaviors>
<local:SwipeInteractionBehavior cm:Message.Attach="[Event LeftSwipe] = [LeftSwipe($source, $eventArgs)]" />
</i:Interaction.Behaviors>
<Grid>
<StackPanel>
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemContentTextBlockStyle}" />
<TextBlock Text="{Binding Url}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />
<TextBlock Text="{Binding Tags, Converter={StaticResource ListToString}}" />
</StackPanel>
</Grid>
</Border>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I ran in an exception if I raise the LeftSwipe event, this is my StackTrace:
System.Exception was not handled.
HResult=-2146233088
Message=No target found for method LeftSwipe.
Source=Caliburn.Micro.Platform
StackTrace:
at Caliburn.Micro.ActionMessage.Invoke(Object eventArgs)
at Caliburn.Micro.TriggerAction`1.Execute(Object sender, Object parameter)
at Microsoft.Xaml.Interactivity.Interaction.ExecuteActions(Object sender, ActionCollection actions, Object parameter)
at Microsoft.Xaml.Interactions.Core.EventTriggerBehavior.OnEvent(Object sender, Object eventArgs)
at ReaderApp.SwipeInteractionBehavior.<>c__DisplayClass5.<OnLeftSwipe>b__4()
at ReaderApp.Extensions.FrameworkElementExtension.<>c__DisplayClass2.<Animate>b__0(Object s, Object e)
InnerException:
ViewModel:
public class MainViewModel : ViewModelBase
{
private readonly IEventAggregator eventAggregator;
private readonly Database database;
public BindableCollection<Link> Links
{
get;
private set;
}
public MainViewModel(INavigationService navigationService, IEventAggregator eventAggregator, Database database)
: base(navigationService)
{
this.eventAggregator = eventAggregator;
this.database = database;
Links = new BindableCollection<Link>();
}
public async void LeftSwipe(object sender, EventArgs e)
{
// ...
}
public void RightSwipe(object sender, EventArgs e)
{
// ...
}
}
So the problem is that
ActionMessage
inheritsTriggerAction<FrameworkElement>
which means it can't attach correctly toSwipeInteractionBehavior
.It's also complicated by the fact there's some major API differences between the WPF / Silverlight / Windows Phone 8 Interactivity SDK and the WinRT Interactivity SDK. You can see a bit of what I mean in the Parser comments.
What I'd recommend is implementing
SwipeInteractionBehavior
as a Trigger Behaviour much likeEventTriggerBehavior
, this used to be a separate base class but with WinRT it's stillIBehavior
, the difference is that it has a property called Actions of typeActionCollection
. Stupidly there is no interface is base class enforcing this so Caliburn.Micro is stuck making some assumptions.You'd then use
Interaction.ExecuteActions
to trigger those actions, in the end your xaml should look something like.It's a bit more long winded, but we need to work around the limitations imposed by the changes in the SDK.