在WPF中如何获取Checkbox的值且不获取DisconnectedItem?
在WPF中获取Checkbox值时避免遇到DisconnectedItem的解决方案
我之前在做WPF项目的时候也踩过这个坑——从ListBox里的Checkbox获取值时碰到了DisconnectedItem,多半是因为UI控件的Items集合里混进了已经和数据源断开绑定的无效项。结合你的XAML代码片段,给你几个实用的解决办法:
先补全你提供的XAML代码(完善ItemTemplate部分,方便理解场景):
<Window x:Class="simple.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:simple" Title="MainWindow" ResizeMode="NoResize" Height="500" Width="530"> <Window.Resources> <Style TargetType="{x:Type ListBox}"> <Setter Property="ItemTemplate"> <Setter.Value> <DataTemplate> <Border BorderBrush="Black" BorderThickness="4" CornerRadius="5" Margin="6"> <CheckBox Content="{Binding ItemName}" IsChecked="{Binding IsSelected, Mode=TwoWay}" /> </Border> </DataTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <ListBox x:Name="MyListBox" ItemsSource="{Binding MyItems}" /> <Button Content="获取选中项" Click="GetCheckedItems_Click" HorizontalAlignment="Bottom" Margin="20" /> </Grid> </Window>
1. 优先从数据源获取(最推荐)
这是完全符合WPF设计理念的做法,彻底避开UI内部的状态问题。假设你的数据源是ObservableCollection<MyItem>(实现INotifyPropertyChanged的实体类):
实体类代码
using System.ComponentModel; using System.Runtime.CompilerServices; namespace simple { public class MyItem : INotifyPropertyChanged { private bool _isSelected; public bool IsSelected { get => _isSelected; set { _isSelected = value; OnPropertyChanged(); } } public string ItemName { get; set; } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
获取选中项的代码
using System.Collections.ObjectModel; using System.Linq; using System.Windows; namespace simple { public partial class MainWindow : Window { public ObservableCollection<MyItem> MyItems { get; set; } = new ObservableCollection<MyItem>(); public MainWindow() { InitializeComponent(); DataContext = this; // 模拟添加测试数据 MyItems.Add(new MyItem { ItemName = "选项1" }); MyItems.Add(new MyItem { ItemName = "选项2" }); } private void GetCheckedItems_Click(object sender, RoutedEventArgs e) { // 直接从数据源筛选,完全绕过UI的Items集合 var checkedItems = MyItems.Where(item => item.IsSelected).ToList(); // 这里处理选中项即可 } } }
这种方式完全和UI解耦,不管UI内部有没有DisconnectedItem,都能准确拿到有效数据。
2. 遍历UI Items时过滤无效项(临时 workaround)
如果因为某些原因必须从ListBox.Items获取数据,可以在遍历的时候跳过DisconnectedItem:
private void GetCheckedItems_Click(object sender, RoutedEventArgs e) { var checkedItems = new List<MyItem>(); foreach (var rawItem in MyListBox.Items) { // 判断并跳过DisconnectedItem if (rawItem.ToString() == "{DisconnectedItem}") { continue; } var myItem = rawItem as MyItem; if (myItem?.IsSelected == true) { checkedItems.Add(myItem); } } // 处理选中项 }
注意:这种方式依赖WPF内部的实现细节,不建议长期使用,后续版本可能会有变化。
3. 刷新CollectionView清除无效项
如果你的ListBox使用了ICollectionView(比如做了排序、过滤),可以先刷新视图再获取数据:
using System.Windows.Data; using System.Linq; private void GetCheckedItems_Click(object sender, RoutedEventArgs e) { var view = CollectionViewSource.GetDefaultView(MyListBox.ItemsSource); view.Refresh(); // 刷新视图,清除无效的DisconnectedItem var checkedItems = MyListBox.Items.Cast<MyItem>().Where(item => item.IsSelected).ToList(); }
总结一下:优先使用第一种从数据源获取的方案,既能避免DisconnectedItem问题,又符合WPF的MVVM设计思想,代码也更简洁易维护。
内容的提问来源于stack exchange,提问作者Arya
相关产品推荐
相关产品推荐

