在没有ItemsSource绑定的情况下将.txt文件读取到列表框,或者在不清除行列表框的情况下删除绑定

问题描述

我对C#相当陌生,但了解基本概念。

我目前正在处理Uni作业,我必须在列表框中将多个文本框作为一个条目输入,然后将所有条目保存到文本文件中。我还需要能够加载文本文件并将新条目添加到列表中。

我已经弄清楚了如何将数据保存到.txt文件,以及如何使用.pp将.txt文件重新加载到列表框中。

if (File.Exists("PersonalFile.txt"))
{
 string[] line = File.ReadAllLines("PersonalFile.txt");
 lbxStaffDetails.ItemsSource = line;
}

但是,由于无法进行数据绑定,因此无法将新条目添加到列表框中,因此出现此错误消息 system.invalidOperationException:'在使用ItemsSource时操作无效。而是使用ItemsControl.ItemsSource访问和修改元素。'

是否可以删除绑定但将数据保留在列表框中?使用lbxStaffDetails.ItemsSource = null;清除列表框;还是有另一种方法可以将.txt文件的所有行都读取到列表框中,而无需将该文件用作绑定源?

注意:

  • lbxStaffDetails是有问题的此列表框
  • PersonalFile.txt是.txt,用于保存新行中的条目。
  • 这是我第一次绑定数据和文件

编辑:

忘记提及我是如何将数据添加到列表框中的,因此这里是代码

private void btnAddWaitingList_Click(object sender,RoutedEventArgs e)
{
 _EmployeeID = tbxEmployeeID.Text;
 _Name = tbxName.Text;
 _PayRate = tbxPayRate.Text;            
 _Email = tbxEmail.Text;

 string employeeDetails = _EmployeeID + "," + _Name + "," + _PayRate + "," + _Email;

 lbxStaffDetails.Items.Add(employeeDetails);
}

代码触发并到达最底行时,它将引发上述错误

解决方法

不要将数据绑定与简单的值分配混淆。数据绑定是一个不同的概念,其中目标使用Binding绑定到数据源。 Binding将监视目标和源,并将更改从一个委派到另一个。这是双向动态数据链接。
您可以在XAML或C#中设置Binding(请参见Data binding overview in WPF)。

您没有将ListBox绑定到文件。您已将文件内容读取为字符串数组。然后,将此数组分配给ListBox.ItemsSource属性。

由于使用ListBox属性填充了ItemsSource,因此不允许使用Items属性(InvalidOperationException)修改其项目。
您必须将修改后的集合再次分配给ListBox.ItemsSource(这将导致完整的ListBox重新创建所有项目,这对性能不利)或使用ObservableCollection。 / p>

这是一个特殊的集合,可以观察到(观察者模式)。观察者会通过事件通知观察者集合已更改(添加/移动/删除)。每个ItemsControl都可以收听此事件,并且会自动更新。

MainWindow.xaml.cs

partial class MainWindow : Window
{
  public ObservableCollection<string> StaffDetails { get; set; }

  public MainWindow()
  {
    InitializeComponent();

    // Set the DataContext to MainWindow for data binding (XAML version)
    this.DataContext = this;
  }

  private void ReadFile()
  {    
    if (!File.Exists("PersonalFile.txt"))
    {
      return;
    }
     
    string[] lines = File.ReadAllLines("PersonalFile.txt");
    
    // Create a new ObservableCollection and initialize it with the array
    this.StaffDetails = new ObservableCollection<string>(lines);

    // You write to the file using this same collection directly,// without accessing the ListBox
    File.WriteAllLines("PersonalFile.txt",this.StaffDetails);
    
    // Option 1: assignment (static data link)
    this.lbxStaffDetails.ItemsSource = this.StaffDetails;
    
    // Alternative option 2: C# data binding (dynamic data link)
    var binding = new Binding(nameof(this.StaffDetails)) { Source = this };
    this.lbxStaffDetails.SetBinding(ItemsControl.ItemsSourceProperty,binding);
    
    // Alternative option 3 (recommended): XAML data binding (dynamic data link). See MainWindow.xaml
  }

  private void btnAddWaitingList_Click(object sender,RoutedEventArgs e)
  {
    _EmployeeID = tbxEmployeeID.Text;
    _Name = tbxName.Text;
    _PayRate = tbxPayRate.Text;            
    _Email = tbxEmail.Text;
    
    var employeeDetails = $"{_EmployeeID},{_Name},{_PayRate},{_Email}";
    
    // Modify the ObservableCollection. 
    // Since ListBox is observing this collection,it will automatically update itself
    this.StaffDetails.Add(employeeDetails);
  }
}

MainWindow.xaml

<Window>

  <!-- Alternative option 3: XAML data binding (recommended) -->
  <ListBox x:Name="lbxStaffDetails" 
           ItemsSource="{Binding StaffDetails}" />
</Window>