#c# #wpf #text-files #listboxitem #itemssource
#c# #wpf #текстовые файлы #элемент списка #itemssource
Вопрос:
Я довольно новичок в C #, но понимаю основные концепции.
В настоящее время я работаю над назначением Uni, где мне нужно ввести несколько текстовых полей как одну запись в listbox, а затем сохранить все записи в текстовый файл. Мне также нужно иметь возможность загружать текстовый файл и добавлять новые записи в список.
Я выяснил, как сохранить данные в файл .txt, а также перезагрузить файл .txt обратно в listbox с помощью
if (File.Exists("PersonalFile.txt"))
{
string[] line = File.ReadAllLines("PersonalFile.txt");
lbxStaffDetails.ItemsSource = line;
}
Однако, делая это таким образом, я не могу добавлять новые записи в listbox из-за привязки данных, я получаю это сообщение об ошибке System.Исключение InvalidOperationException: ‘Операция недопустима, пока используется ItemsSource. Доступ и изменение элементов с помощью ItemsControl.Вместо этого используется ItemsSource.’
Есть ли способ удалить привязку, но сохранить данные в listbox? Использование lbxStaffDetails.ItemsSource = null;
очищает listbox; или есть другой способ прочитать все строки файла .txt в listbox без использования файла в качестве источника привязки?
Примечания:
- lbxStaffDetails об этом listbox идет речь
- PersonalFile.txt содержит ли файл .txt записи в новых строках.
- Это первый раз, когда я связываю данные и файлы.
Редактировать:
Забыл упомянуть, как я добавляю данные в listbox, поэтому вот код для этого.
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);
}
Когда код запускается и доходит до нижней строки, он выдает ошибку, упомянутую выше.
Комментарии:
1. В вашем вопросе недостаточно подробностей, чтобы дать хороший ответ. Но ваша проблема, похоже, коренится в том факте, что вы неправильно обрабатываете связанные свойства модели. В частности, единственная цель модели представления, содержащей свойства для привязки, заключается в том, чтобы эти свойства отражали то, что представление должно представлять в любой момент времени. Должна быть коллекция (например
ObservableCollection<string>
), привязанная кListBox.ItemsSource
(в XAML, не назначенная в code-behind), и эта коллекция должна быть заполнена путем копирования в нее данных, считанных из файла. …2. …
string[]
ВозвращаемыйFile.ReadAllLines()
сам по себе не является коллекцией для использованияListBox
. Хотя, в качестве альтернативы, если вы хотите использовать его таким образом, вам следует привязатьItemSource
кstring[]
свойству в модели представления и обновить это свойство с помощьюstring[]
чтения из файла при чтении файла. Другие изменения в представлении пользователю должны обрабатываться аналогичным образом, всегда опосредованно через модель представления, при этом базовая «бизнес-логика» обрабатывается отдельно от этой модели представления.3. Поскольку вы хотите иметь возможность добавлять элементы в
ListBox
один за раз, когда пользователь вводит данные, вам, вероятно, следует пойти поObservableCollection<T>
маршруту. Добавление в эту коллекцию автоматически обновит,ListBox
если вы правильно привязали коллекцию кItemsSource
.
Ответ №1:
Не путайте привязку данных с простым присвоением значения. Привязка данных — это другая концепция, когда цель привязывается к источнику данных с помощью Binding
. Binding
будет отслеживать цель и источник и передавать изменения от одного к другому. Это двунаправленный динамический канал передачи данных.
Вы можете настроить Binding
в XAML или C # (см. Обзор привязки данных в WPF).
Вы не привязываете ListBox
к файлу. Вы прочитали содержимое файла в массив строк. Затем этот массив присваивается ListBox.ItemsSource
свойству.
Поскольку вы заполнили его, ListBox
используя ItemsSource
свойство, вам не разрешается изменять его элементы с помощью Items
свойства ( InvalidOperationException
).
Вам нужно либо снова назначить измененную коллекцию ListBox.ItemsSource
(что приведет к повторному созданию всех элементов complete ListBox
, что плохо сказывается на производительности), либо использовать ObservableCollection
.
Это специальная коллекция, которая позволяет наблюдать (шаблон наблюдателя). Наблюдатель получает уведомление от наблюдаемой коллекции через событие, что коллекция изменилась (добавить / переместить / удалить). Каждый 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>