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
相关产品推荐
相关产品推荐

