I have successfully bound a DrogGestureRecognizer's Drop event to the CodeBehind using XAML markup as shown below:
<Label Text="MyTestItem" >
<Label.GestureRecognizers>
<DropGestureRecognizer AllowDrop="True" Drop="DropGestureRecognizer_Drop_Item"/>
</Label.GestureRecognizers>
</Label>
However I need to accomplish the same thing in c# code as I am creating a view/control that must be dynamically built due to recursion. My requirement is that I get both the arguments from the event (sender and DropEventArgs). I'm open to a solution that works with the CodeBehind or the ViewModel.
Below is my attempt, however I'm struggling with the MultiBinding. You can see my comments in the code:
RelativeBindingSource rbs2 = new RelativeBindingSource(RelativeBindingSourceMode.FindAncestorBindingContext, ancestorType: typeof(TreeViewPageViewModel));
DropGestureRecognizer dropgGr = new DropGestureRecognizer { AllowDrop = true };
dropgGr.Bind(DropGestureRecognizer.DropCommandProperty,
mode: BindingMode.OneTime,
source: rbs2,
path: "DropGestureRecognizerDropCommand"
);
dropgGr.SetBinding(DropGestureRecognizer.DropCommandParameterProperty, new MultiBinding
{
Bindings = new Collection<BindingBase>
{
new Binding("."), // Is this the sender?
new Binding("") // How to set the DropEvenArgs here? x:TypeArguments="DropEventArgs"
}
});
label.GestureRecognizers.Add(dropgGr);
SOLVED: The goal is to allow my control to drag and drop from one label to another label inside the control, not external desktop drag/drop integration. I have been able to attach a Flyout menu to my label and a TapGestureRecognizer and get it to successfully call a command in my ViewModel with the code below.
RelativeBindingSource rbs = new RelativeBindingSource(RelativeBindingSourceMode.FindAncestorBindingContext, ancestorType: typeof(ITreeViewPageViewModel));
// Context Menu --------------------------------------
var menuItem1 = new MenuFlyoutItem
{
Text = "Delete Item",
CommandParameter = xamlItem.ItemId
};
menuItem1.Bind(MenuFlyoutItem.CommandProperty,
mode: BindingMode.OneTime,
source: rbs,
path: "DeleteItemCommand"
);
var menuFlyout = new MenuFlyout();
menuFlyout.Add(menuItem1);
FlyoutBase.SetContextFlyout(label, menuFlyout);
// TagGesture ----------------------------------------
TapGestureRecognizer tgr = new TapGestureRecognizer
{
Buttons = ButtonsMask.Primary,
CommandParameter = xamlItem.ItemId,
NumberOfTapsRequired = 2
};
tgr.Bind(TapGestureRecognizer.CommandProperty,
mode: BindingMode.OneTime,
source: rbs,
path: "ItemSelectedCommand"
);
label.GestureRecognizers.Add(tgr);
In the above examples notice the commandParameter is being set, however in this case the parameter is an ID from my data. What I really need for my DragDrop Gestures, is to attach to the existing Drop "event" rather than a "Command". It turns out it was surpisingly easy:
DropGestureRecognizer dropGr = new DropGestureRecognizer { AllowDrop = true };
dropGr.Drop += DropGr_Drop_Item;
label.GestureRecognizers.Add(dropGr);
// This method is in the same class as the above code, and since I need to call a method in my
// ViewModel you can see the last line that is used to accomplish this.
private void DropGr_Drop_Item(object? sender, DropEventArgs e)
{
var data = e.Data.Properties["Text"].ToString();
var sourceItemId = e.Data.Properties["ItemId"].ToString();
var label = (sender as Element)?.Parent as Label;
var targetItemId = label.StyleId.Substring(5);
(this.BindingContext as ITreeViewPageViewModel).ReOrderItems(sourceItemId, targetItemId);
}
What I really needed for my DragDrop Gestures was to attach to the existing Drop "event" rather than a "Command". It turns out it was surpisingly easy:
DropGestureRecognizer dropGr = new DropGestureRecognizer { AllowDrop = true };
dropGr.Drop += DropGr_Drop_Item;
label.GestureRecognizers.Add(dropGr);
// This method is in the same class as the above code, and since I need to call a method in my
// ViewModel you can see the last line that is used to accomplish this.
private void DropGr_Drop_Item(object? sender, DropEventArgs e)
{
var data = e.Data.Properties["Text"].ToString();
var sourceItemId = e.Data.Properties["ItemId"].ToString();
var label = (sender as Element)?.Parent as Label;
var targetItemId = label.StyleId.Substring(5);
(this.BindingContext as ITreeViewPageViewModel).ReOrderItems(sourceItemId, targetItemId);
}