如何将 ListBox 中的多个选定项目移回另一个 ListBox?

How to move multiple selected items in a ListBox back to another ListBox?

我已成功将 LeftListBox 中的多个项目移动到 RightListBox。现在,我想将它们从 RightListBox 移回 LeftListBox。但是,它给了我 "System.NullReferenceException"。这是我的代码:

MainWindow.xaml.cs

using ListBoxMoveAll.Model;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;

namespace ListBoxMoveAll
{
    public partial class MainWindow : Window
    {
        ObservableCollection<TestModel> testItem = new ObservableCollection<TestModel>();

        public MainWindow()
        {
            InitializeComponent();

            testItem.Add(new TestModel("Test_1"));
            testItem.Add(new TestModel("Test_2"));
            testItem.Add(new TestModel("Test_3"));
            LeftListBox.ItemsSource = testItem;

            CollectionViewSource.GetDefaultView(LeftListBox.ItemsSource).Filter =
                (tm) => !RightListBox.Items.Cast<TestModel>().Any(x => x.Equals(tm as TestModel));
            CollectionViewSource.GetDefaultView(RightListBox.ItemsSource);
        }

        private void Add_Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (var item in LeftListBox.SelectedItems)
            {
                RightListBox.ItemsSource = null;
                RightListBox.Items.Add(item);
            }
            CollectionViewSource.GetDefaultView(LeftListBox.ItemsSource).Refresh();
        }

        private void Remove_Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (var item in RightListBox.SelectedItems)
            {
                LeftListBox.ItemsSource = null;
                LeftListBox.Items.Add(item);
            }
            CollectionViewSource.GetDefaultView(RightListBox.ItemsSource).Refresh();
        }
    }
}

MainWindow.xaml

<Window x:Class="ListBoxMoveAll.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ListBoxMoveAll"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <ListBox x:Name="LeftListBox" Grid.Column="0" Grid.Row="1" Grid.RowSpan="3" 
                 SelectionMode="Extended" DisplayMemberPath="TestItem">
        </ListBox>
        <ListBox x:Name="RightListBox" Grid.Column="2" Grid.Row="1" Grid.RowSpan="3" DisplayMemberPath="TestItem" />
        <StackPanel Grid.Column="1" Grid.Row="1" VerticalAlignment="Center">
            <Button Content="Add" x:Name="Add_Button" Click="Add_Button_Click"/>
        </StackPanel>
        <StackPanel Grid.Column="1" Grid.Row="3" VerticalAlignment="Center">
            <Button Content="Remove" x:Name="Remove_Button" Click="Remove_Button_Click"/>
        </StackPanel>
    </Grid>
</Window>

Model/TestModel.cs

namespace ListBoxMoveAll.Model
{
    public class TestModel
    {
        public TestModel(string _testItem) 
        { TestItem = _testItem; }

        public string TestItem { get; set; }
    }
}

我加了RightListBox.ItemsSource = null;。我认为我对 CollectionViewSource.GetDefaultView 的用法有问题,但我想不通。 请帮我。提前谢谢你。

问题是您在 null 上调用 CollectionViewSource.GetDefaultView。 RightListBox.ItemsSource 为空,因为您在 Add_Button_Click 处理程序中将其设置为空。

解决办法是LeftListBox只引用ItemsSource(因为你在构造函数中设置了),RightListBox引用Items。

然后您将得到如下代码:

public partial class MainWindow : Window
{
    ObservableCollection<TestModel> testItem = new ObservableCollection<TestModel>();
    public MainWindow()
    {
        InitializeComponent();

        testItem.Add(new TestModel("Test_1"));
        testItem.Add(new TestModel("Test_2"));
        testItem.Add(new TestModel("Test_3"));
        LeftListBox.ItemsSource = testItem;
        CollectionViewSource.GetDefaultView(LeftListBox.ItemsSource).Filter = (tm) => !RightListBox.Items.Cast<TestModel>().Any(x => x.Equals(tm as TestModel));
    }

    private void Add_Button_Click(object sender, RoutedEventArgs e)
    {
        foreach (TestModel item in LeftListBox.SelectedItems)
            RightListBox.Items.Add(item);

        CollectionViewSource.GetDefaultView(LeftListBox.ItemsSource).Refresh();
    }

    private void Remove_Button_Click(object sender, RoutedEventArgs e)
    {
        foreach (TestModel item in RightListBox.SelectedItems.OfType<TestModel>().ToList())
            RightListBox.Items.Remove(item);

        CollectionViewSource.GetDefaultView(LeftListBox.ItemsSource).Refresh();
    }
}

但是您应该记住,LeftListBox 的 ItemsSource 始终包含所有值,它只是根据右侧列表中的 Items 在视觉上进行过滤。

如果您希望 LeftListBox 和 RightListBox 的 ItemsSource 相互改变,您应该考虑如下更改 xaml:

<ListBox
    x:Name="LeftListBox"
    Grid.Row="1"
    Grid.RowSpan="3"
    Grid.Column="0"
    DisplayMemberPath="TestItem"
    ItemsSource="{Binding LeftListBoxItems}"
    SelectionMode="Extended" />
<ListBox
    x:Name="RightListBox"
    Grid.Row="1"
    Grid.RowSpan="3"
    Grid.Column="2"
    DisplayMemberPath="TestItem"
    ItemsSource="{Binding RightListBoxItems}" />

你的代码如下:

public partial class MainWindow : Window
{
    public ObservableCollection<TestModel> LeftListBoxItems { get; } = new ObservableCollection<TestModel>();
    public ObservableCollection<TestModel> RightListBoxItems { get; } = new ObservableCollection<TestModel>();

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        LeftListBoxItems.Add(new TestModel("Test_1"));
        LeftListBoxItems.Add(new TestModel("Test_2"));
        LeftListBoxItems.Add(new TestModel("Test_3"));
    }

    private void Add_Button_Click(object sender, RoutedEventArgs e)
    {
        foreach (TestModel item in LeftListBox.SelectedItems.OfType<TestModel>().ToList())
        {
            LeftListBoxItems.Remove(item);
            RightListBoxItems.Add(item);
        }
    }

    private void Remove_Button_Click(object sender, RoutedEventArgs e)
    {
        foreach (TestModel item in RightListBox.SelectedItems.OfType<TestModel>().ToList())
        {
            RightListBoxItems.Remove(item);
            LeftListBoxItems.Add(item);
        }
    }
}