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

Xamarin.Forms:如何根据条件控制ListView中Switch的开关状态?

解决Switch绑定IsToggled时的NotImplementedException及逻辑优化问题

先说说你遇到的异常原因

你看到的System.NotImplementedException是因为IsToggled属性默认是双向绑定的——当用户手动切换Switch时,Xamarin.Forms会自动调用转换器的ConvertBack方法,试图把布尔值(Switch的状态)转换回数据源的类型,但你的转换器里这个方法直接抛出了未实现的异常,这就是问题所在。

第一步:修复转换器,实现双向绑定逻辑

我们需要完善转换器的两个方法,同时还要让ConvertBack能拿到当前操作的userId,所以先修改XAML的绑定,把userId作为参数传给转换器:

<Switch 
    IsToggled="{Binding userProfileTO.userId, 
                        Converter={StaticResource userIdExistConverter},
                        ConverterParameter={Binding userProfileTO.userId}}" 
    HorizontalOptions="EndAndExpand" 
    VerticalOptions="CenterAndExpand"/>

(另外建议去掉Toggled="OnToggledEvent",因为转换器的ConvertBack会处理状态更新,避免重复逻辑)

然后更新转换器代码,同时优化拆分逻辑(处理空字符串、空元素的情况):

class UserIdExistConverter : IValueConverter 
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // 处理空值或未初始化的情况
        if (value == null || !Application.Current.Properties.ContainsKey("GroupUserIds"))
            return false;

        string currentUserId = value.ToString();
        string storedUserIds = Application.Current.Properties["GroupUserIds"].ToString();

        // 拆分时自动移除空元素,避免空字符串干扰判断
        var userIdList = storedUserIds.Split(',', StringSplitOptions.RemoveEmptyEntries);
        return userIdList.Contains(currentUserId);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool isSwitchOn = (bool)value;
        string currentUserId = parameter.ToString();

        // 初始化存储的用户ID字符串(如果不存在)
        if (!Application.Current.Properties.ContainsKey("GroupUserIds"))
        {
            Application.Current.Properties["GroupUserIds"] = isSwitchOn ? currentUserId : string.Empty;
            _ = Application.Current.SavePropertiesAsync();
            return currentUserId;
        }

        string existingIds = Application.Current.Properties["GroupUserIds"].ToString();
        var userIdList = existingIds.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList();

        // 根据Switch状态添加/移除当前用户ID
        if (isSwitchOn)
        {
            if (!userIdList.Contains(currentUserId))
                userIdList.Add(currentUserId);
        }
        else
        {
            userIdList.Remove(currentUserId);
        }

        // 重新拼接并保存
        string updatedIds = string.Join(',', userIdList);
        Application.Current.Properties["GroupUserIds"] = updatedIds;
        // 异步保存,避免阻塞UI
        _ = Application.Current.SavePropertiesAsync();

        // 返回符合绑定要求的值(这里返回userId即可,不影响逻辑)
        return currentUserId;
    }
}

第二步:优化你的IsUserInList方法

你的判断方法逻辑没问题,但需要处理空值、格式异常的情况,避免崩溃:

bool IsUserInList(int userId)
{
    // 先判断存储的键是否存在
    if (!Application.Current.Properties.ContainsKey("GroupUserIds"))
        return false;

    string storedIds = Application.Current.Properties["GroupUserIds"].ToString();
    // 处理空字符串的情况
    if (string.IsNullOrWhiteSpace(storedIds))
        return false;

    try
    {
        // 拆分时去除空元素,同时处理可能的空格
        var userIdList = storedIds.Split(',', StringSplitOptions.RemoveEmptyEntries)
                                .Select(id => int.Parse(id.Trim()))
                                .ToList();
        return userIdList.Contains(userId);
    }
    catch (FormatException)
    {
        // 捕获无效数字格式的异常,避免崩溃
        Debug.WriteLine($"警告:GroupUserIds中存在无效的数字格式:{storedIds}");
        return false;
    }
}

额外注意事项

  • 建议在App启动时初始化GroupUserIds键,避免首次使用时空引用:
    public App()
    {
        InitializeComponent();
        if (!Application.Current.Properties.ContainsKey("GroupUserIds"))
        {
            Application.Current.Properties["GroupUserIds"] = string.Empty;
        }
    }
    
  • 调用SavePropertiesAsync()是必须的,否则修改后的属性不会被持久化到本地存储。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:52:27