问题描述
我对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>