Я новичок в C# WPF и пытаюсь создать приложение, которое использует DataTable и записывает эту DataTable в файл XML с помощью метода DataTable.WriteXML(). Затем файл XML считывается DataGrid из ListView (selectedList).
private void refreshDataGrid(DataGrid dataGridName, ListView selectedList, string path)
{
FileStream file;
//check if the item from ListView is selected
if (selectedList.SelectedItem != null)
{
try
{
file = File.Open(path + "\\" + selectedList.SelectedItem.ToString() + ".xml", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
catch (Exception x)
{
MessageBox.Show(x.Message.ToString());
return;
}
//clear the defaultData DataSet so it doesn't have any content
defaultData.Tables.Clear();
//read XML file
defaultData.ReadXml(file);
file.Close();
dataGridName.ItemsSource = defaultData.Tables[0].DefaultView;
}
DataGrid доступен для редактирования пользователем, и когда он выполняет редактирование содержимого, оно сохраняется в файле XML, а затем FileWatcher отслеживает изменения в последнем доступе к файлу, поэтому, когда содержимое файла изменяется, datagrid будет обновлен.
FileSystemWatcher fileWatcher = new();
private void CreateFileWatcher(string path)
{
fileWatcher.Path = path;
fileWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.Size | NotifyFilters.FileName;
fileWatcher.Filter = "*.xml";
fileWatcher.Changed += FileWatcher_Changed;
fileWatcher.EnableRaisingEvents = true;
}
// Event for filewatcher throws an Exception
private void FileWatcher_Changed(object sender, FileSystemEventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)(() =>
{
try
{
refreshDataGrid(dataGridName, userListView, path);
}
catch(Exception)
{
return;
}
}));
}
Итак, проблема в том, что когда я создаю НОВЫЙ XML-ФАЙЛ во время работы приложения, а затем пользователь открывает этот файл в DataGrid и редактирует поле в DataGrid, данные сохраняются в XML-файл, как и должно быть. , и FileWatcher вызывается, поэтому, когда FileWatcher пытается обновить Datagrid, я получаю это сообщение:
Не удалось найти UIElementAutomationPeer.cs Вам нужно найти UIElementAutomationPeer.cs для просмотра источника текущего вызова. кадр стека System.ArgumentNullException: «Значение не может быть нулевым. Arg_ParamName_Name».
Необработанное исключение типа «System.ArgumentNullException» в PresentationCore.dll Значение не может быть нулевым.
Когда я создаю файл XML и перезапускаю приложение, все работает нормально. Также, когда файл был создан до запуска приложения, FileWatcher работает нормально. Я предполагаю, что вновь созданные файлы (во время выполнения приложения) не обновляются самим приложением, и ему необходимо обновить пользовательский интерфейс, но я не знаю, как это сделать. Мой FileWatcher также является глобальным, поэтому, возможно, это может быть проблемой, или мне следует как-то обновить FileWatcher? Будем признательны за любую помощь.
РЕДАКТИРОВАТЬ: я думаю, что есть проблема при создании файла в моей программе, возможно, приложение хочет использовать один и тот же файл дважды или не может получить к нему доступ, вот код:
private void saveTableToXML()
{
DataTable dt = new DataTable();
dt = ((DataView)dataGridName.ItemsSource).ToTable();
try
{
FileStream file = File.Create(path + "\\.xml");
dt.WriteXml(file, XmlWriteMode.WriteSchema,false);
file.Close();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
Можете ли вы опубликовать сообщение об исключении и стек вызовов. Эта ошибка кажется чем-то, что IDE покажет, если в нее не загружены PDB. Не фактическое исключение.
Стек вызовов: PresentationCore.dll!System.Windows.Automation.Peers.UIElementAutomationPeer.FromElement (элемент System.Windows.UIElement) Строка 70 C#
Сообщение об исключении: {"Значение не может быть нулевым. (Параметр "элемент")"} System.ArgumentNullException
Какая строка кода выше вызывает это исключение? Вы можете отредактировать свой вопрос, поместив его в код, например
//this line throws the exception
. Лучше, чем комментировать, чтобы все могли видеть это в вопросе. Я бы также предложил установить точку останова вrefreshDataGrid
и выполнить метод построчно, чтобы вы могли убедиться, что он делает то, что вы думаете.Я отлаживал refeshDataGrid, но он отлично работает до последней строки кода, теперь я отредактировал вопрос.
Итак, эта строка
dataGridName.ItemsSource = defaultData.Tables[0].DefaultView;
выдает исключение? Это было бы моим предположением. Проверьте эти значения, возможно, это не то, что вам нужно. Может быть, нет таблицы или представления по умолчанию?Нет, исключение каким-то образом вызывается функцией FileSystemWatcher, ItemsSource успешно изменяется
Хорошо, какая линия бросает? Если у вас подключен отладчик, он выделит строку кода. Это блок try catch, который у вас есть в событии? Я бы избавился от этого или сделал что-то полезное с исключением.
FileWatcher_Changed() выдает исключение, чтобы было ясно: если я удаляю refreshDataGrid() из FileWatcher_Changed(), он работает нормально, потому что после удаления он ничего не делает.
Это означает, что какая-то строка в
refreshDataGrid
выбрасывается. Нам нужна эта линия. Или это то, как вы его вызываете. Вы можете просто сделатьthis.BeginInvoke
. Вы также можете проверитьInvokeRequired
, чтобы узнать, находитесь ли вы уже в потоке GUI.Я добавил окно сообщений после refreshDataGrid() в FileWatcher_Changed(), и отображается MessageBox, так что это означает, что refreshDataGrid() не бросает, я думаю
Моя первоначальная мысль заключалась в том, что файл читается, пока он еще записывается. Наблюдатель за файлами прослушивает целую кучу вещей. Если я правильно понимаю, это одно и то же приложение пишет и читает файл, поэтому я вообще не понимаю необходимости в наблюдателе за файлами. Почему бы просто не подать внутренний сигнал о том, что происходит? Кроме того, записывайте в средство просмотра (консоль?), что происходит, вместо использования отладчика.
Я думаю, но я не уверен, что наблюдатель за файлами вызовет свое событие до того, как измененный файл будет закрыт. В качестве теста. Поставьте небольшую задержку и посмотрите, что произойдет.
Правильно ли я понимаю, что ваша программа создает строку в таблице данных, записывает таблицу данных на диск, использует fsw для обнаружения записываемого файла, загружает его с диска и отображает в таблице данных? Знаете ли вы, что вы можете полностью исключить диск и fsw из него и заставить строку отображаться в сетке с помощью всего одной строки кода? Передача данных между различными частями вашей программы путем их записи на диск и обратного чтения смехотворна..
Я добавил свой код для создания нового XML-файла в своем приложении. Возможно ли, что я неправильно закрыл файл?