I've got a custom control called MovingFrame. It's a drag-n-drop control. When dropping a dragged item onto another item a DropReceived event is fired. I've got it working with code in code behind but I would like to be able just to bind in XAML. For some reason I always get the following error message:
XFC0009 No property, BindableProperty, or event found for "DropReceived", or mismatching type between value and property.
The solution below works fine but I need code behind code to solve it. I didn't find a solution that solely depends on XAML.
The (partial) code of the custom control looks like this.
public class MovingFrame : Frame, IDragAndDropMovingView, IDragAndDropHoverableView, IDragAndDropReceivingView
{
public delegate void DropReceivedEventHandler(object sender, DropReceivedEventArgs e);
public event DropReceivedEventHandler DropReceived;
public void OnDropReceived(IDragAndDropMovingView view)
{
DropReceived?.Invoke(this, new DropReceivedEventArgs(view));
}
protected override void OnParentSet()
{
base.OnParentSet();
this.InitializeDragAndDrop();
}
}
Here's the implementation in XAML:
<?xml version="1.0" encoding="utf-8" ?>
<forms:MvxContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:forms="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
xmlns:views="clr-namespace:eTabber.Views"
xmlns:viewmodels="clr-namespace:eTabber.Core.ViewModels;assembly=eTabber.Core"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tgb="clr-namespace:TGB.Xamarin.Forms.DragAndDrop;assembly=TGB.Xamarin.Forms"
mc:Ignorable="d"
Padding="0"
x:Class="eTabber.Views.SetView" x:TypeArguments="viewmodels:SetlistViewModel"
Title="{Binding PageTitle}" >
<StackLayout
StyleClass="MainContainer"
Spacing="0"
Margin="0"
Padding="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Text="{Binding SetList.Name, Mode=OneWay}" StyleClass="Title" Grid.Row="0"></Label>
<StackLayout Orientation="Horizontal" Grid.Row="1">
<Button Text="Add" Command="{Binding AddCommand}" />
</StackLayout>
<!--<ScrollView Margin="0" Padding="0" Orientation="Vertical" Grid.Row="2">-->
<StackLayout BindableLayout.ItemsSource="{Binding SetItems}" x:Name="SetlistsListView" Grid.Row="2">
<BindableLayout.ItemTemplate>
<DataTemplate x:Name="RowTemplate">
<tgb:MovingFrame x:Name="MovingFrame"
Padding="0"
Margin="0"
DropReceived="{Binding DropReceivedHandler}">
<StackLayout Orientation="Vertical">
<Label Text="{Binding Set.SetName, Mode=OneWay}"
IsVisible="{Binding TitleVisible, Mode=OneWay}"
StyleClass="Title"
Grid.Row="0">
</Label>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding Path=Song.Artist.Name, Mode=OneWay}" Grid.Column="0" Grid.Row="0" StyleClass="Label"/>
<Label Text="{Binding Path=Song.Title, Mode=OneWay}" Grid.Column="1" Grid.Row="0" StyleClass="Label"/>
</Grid>
</StackLayout>
</tgb:MovingFrame>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<!--</ScrollView>-->
</Grid>
</StackLayout>
</forms:MvxContentPage>
Code behind with the current solution:
using eTabber.Core.ViewModels;
using MvvmCross.Forms.Views;
using System.ComponentModel;
using TGB.Xamarin.Forms.DragAndDrop;
using TGB.Xamarin.Forms.DragAndDrop.DragAndDropEventArgs;
using Xamarin.Forms;
namespace eTabber.Views
{
[DesignTimeVisible(false)]
public partial class SetView : MvxContentPage<SetlistViewModel>
{
public SetView()
{
InitializeComponent();
SetlistsListView.ChildAdded += SetlistsListView_ChildAdded;
}
private void SetlistsListView_ChildAdded(object sender, ElementEventArgs e)
{
var movingFrame = e.Element as MovingFrame;
if (movingFrame != null)
{
var viewModel = ViewModel as SetlistViewModel;
if (viewModel != null)
{
movingFrame.DropReceived -= MovingFrame_DropReceived;
movingFrame.DropReceived += MovingFrame_DropReceived;
}
}
}
private void MovingFrame_DropReceived(object sender, DropReceivedEventArgs e)
{
var viewModel = ViewModel as SetlistViewModel;
if(viewModel != null)
{
viewModel.DropReceivedHandler(sender, e);
}
}
}
}
And partial viewmodel class (BaseViewModel is based on MvxViewModel):
using eTabber.Data.Model;
using TGB.Xamarin.Forms.DragAndDrop.DragAndDropEventArgs;
using Xamarin.Forms;
namespace eTabber.Core.ViewModels
{
public class SetlistViewModel : BaseViewModel<SetList>
{
public SetlistViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
}
public void DropReceivedHandler(object sender, DropReceivedEventArgs e)
{
}
}
}