MAUI:如何在代码中绑定事件属性(sender、EventArgs)至ViewModel或代码后置
动态创建控件时实现DropGestureRecognizer拖放功能
问题场景
我已经通过以下XAML代码成功将DropGestureRecognizer的Drop事件绑定到代码后置:
<Label Text="MyTestItem" > <Label.GestureRecognizers> <DropGestureRecognizer AllowDrop="True" Drop="DropGestureRecognizer_Drop_Item"/> </Label.GestureRecognizers> </Label>
但现在需要递归动态创建视图/控件,所以得用C#代码实现相同逻辑,要求能获取事件的sender和DropEventArgs参数,同时支持绑定到代码后置或ViewModel。
尝试过程(遇到MultiBinding难题)
我尝试用Command绑定的方式实现,但在MultiBinding部分遇到了问题,代码里的注释是我的疑问:
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("."), // 这是不是sender? new Binding("") // 这里怎么设置DropEventArgs?x:TypeArguments="DropEventArgs" } }); label.GestureRecognizers.Add(dropgGr);
最终解决方案
我的需求是控件内部标签间的拖放,不需要和外部桌面集成。之前已经成功给标签附加了Flyout菜单和TapGestureRecognizer,并通过以下代码调用ViewModel中的命令:
RelativeBindingSource rbs = new RelativeBindingSource(RelativeBindingSourceMode.FindAncestorBindingContext, ancestorType: typeof(ITreeViewPageViewModel)); // 上下文菜单 -------------------------------------- var menuItem1 = new MenuFlyoutItem { Text = "删除项", 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); // 双击手势 ---------------------------------------- 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);
上面的示例是把数据ID设为CommandParameter,但对于拖放手势,我真正需要的是直接附加到现有的Drop事件,而非使用Command。最终发现实现方法非常简单:
DropGestureRecognizer dropGr = new DropGestureRecognizer { AllowDrop = true }; dropGr.Drop += DropGr_Drop_Item; label.GestureRecognizers.Add(dropGr); // 这个方法和上面的代码在同一个类中,因为需要调用ViewModel里的方法,最后一行就是实现方式 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); }
内容的提问来源于stack exchange,提问作者HopDev
相关产品推荐
相关产品推荐

