You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 01:08:37