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

使用MVVM Helpers在Xamarin ViewModel中处理Entry控件Completed事件的问题

解决Entry Completed事件绑定MVVM命令的错误问题

首先,咱们来拆解你遇到的cannot convert from 'void' to 'System.Action'错误:

你在实例化命令时写了这行代码:

UpdatedCost_Dif = new MvvmHelpers.Commands.Command(UpdatedCost_Completed(null,null));

这里的核心问题是你直接执行了方法UpdatedCost_Completed(null,null),这个方法执行后返回void,但Command的构造函数需要的是一个Action委托(也就是无参数的方法引用),不是方法执行后的结果,这就导致了类型不匹配的错误。另外,你的UpdatedCost_Completed方法带了sender和EventArgs参数,而MvvmHelpers的基础Command默认只接受无参数的方法,这也会导致签名不匹配。

下面给你两种可行的解决思路,优先推荐第一种(更贴合MVVM的设计思想):


方案一:通过数据绑定获取输入(推荐的MVVM写法)

在MVVM模式里,我们应该避免直接操作UI控件,而是通过绑定把Entry的文本和ViewModel的属性关联起来。这样代码更简洁,也符合前后端分离的原则。

修改后的XAML代码:

<Entry x:Name="UpdatedCost" Text="{Binding UpdatedCostText}" Completed="{Binding CalculatePriceDiffCommand}"/>

修改后的ViewModel代码:

public class ExistingProductPricingViewModel : BaseViewModel 
{
    // 绑定Entry的Text到这个属性
    private string _updatedCostText;
    public string UpdatedCostText 
    { 
        get => _updatedCostText; 
        set => SetProperty(ref _updatedCostText, value); 
    }

    private int _priceDifference;
    public int PriceDifference 
    { 
        get => _priceDifference; 
        set => SetProperty(ref _priceDifference, value); 
    }

    // 处理Completed事件的命令
    public ICommand CalculatePriceDiffCommand { get; }

    // 把json改成私有只读字段,更符合封装原则
    private readonly string _baseValueJson = "2";

    public ExistingProductPricingViewModel() 
    {
        // 实例化命令,传递方法引用即可,不要直接调用方法
        CalculatePriceDiffCommand = new MvvmHelpers.Commands.Command(CalculatePriceDifference);
    }

    private void CalculatePriceDifference()
    {
        // 用TryParse避免输入非数字时抛出异常
        if (int.TryParse(UpdatedCostText, out int updatedValue))
        {
            int baseValue = int.Parse(_baseValueJson);
            PriceDifference = updatedValue - baseValue;
        }
        else
        {
            // 输入无效时的处理逻辑,比如重置差值
            PriceDifference = 0;
        }
    }
}

这个方案的优势:

  • 完全遵循MVVM的解耦思想,不需要直接操作UI控件
  • 增加了输入合法性校验,避免程序崩溃
  • 代码逻辑清晰,后续维护更方便

方案二:修正原有命令绑定(适合特殊场景)

如果你一定要通过sender获取Entry的文本,可以使用MvvmHelpers的带参数命令Command<object>,把控件实例作为参数传递给命令:

修改后的XAML代码:

<Entry x:Name="UpdatedCost" Completed="Entry_Completed"/>

然后在页面的后台代码(.xaml.cs)里把事件转发给ViewModel的命令:

private void Entry_Completed(object sender, EventArgs e)
{
    if (BindingContext is ExistingProductPricingViewModel vm)
    {
        vm.UpdatedCost_Dif.Execute(sender);
    }
}

修改后的ViewModel代码:

public class ExistingProductPricingViewModel : BaseViewModel 
{
    // 使用带参数的Command<object>
    public ICommand UpdatedCost_Dif { get; }

    int current_diff = 0;
    public string json = "2";
    public int PriceDifference { get => current_diff; set => SetProperty(ref current_diff, value); }

    public ExistingProductPricingViewModel() 
    {
        // 传递方法引用,不要直接调用方法
        UpdatedCost_Dif = new MvvmHelpers.Commands.Command<object>(UpdatedCost_Completed);
    }

    private void UpdatedCost_Completed(object sender) 
    {
        // 先校验控件类型和输入合法性
        if (sender is Entry entry && int.TryParse(entry.Text, out int updated))
        {
            current_diff = updated - int.Parse(json);
            PriceDifference = current_diff;
        }
    }
}

这个方案解决了原有的错误:

  • 用Command<object>适配带参数的方法
  • 实例化命令时传递方法引用,而非直接执行方法
  • 增加了类型检查和安全解析,避免空引用或格式错误异常

总结来说,方案一更符合MVVM的设计理念,也更易于测试和维护,优先推荐使用。如果有特殊需求必须操作控件,再考虑方案二。

内容的提问来源于stack exchange,提问作者Kahalon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 03:52:27