Как сделать импорт файла Excel в свою коллекцию Avalonia
Всем привет, нужна помощь в импорте excel файла в коллекцию. В Excel файле должна быть одна колонка. И текст построчно должен загружаться в коллекцию в объект Text. Для открытия файла нужно использовать OpenFilePicker т.к OpenFileDialog не работает. Путь к файлу выбирает пользователь.
VM:
public class MainWindowViewModel : ViewModelBase
{
private ObservableCollection<Elements> _elementsList;
public ObservableCollection<Elements> ElementsList
{
get => _elementsList;
set => this.RaiseAndSetIfChanged(ref _elementsList, value);
}
public ReactiveCommand<Unit, Unit> AddNewRow { get; set; }
public ReactiveCommand<Unit, Unit> ImportFiles { get; set; }
public MainWindowViewModel()
{
ElementsList = new ObservableCollection<Elements>(new List<Elements>());
ElementsList.Add(new ObservableCollection<Elements>
{
new()
{
Id = ElementsList.Count, Text = ""
}
});
AddNewRow = ReactiveCommand.Create(() =>
{
ElementsList.Add(new ObservableCollection<Elements>
{
new()
{
Id = ElementsList.Count, Text = ""
}
});
});
ImportFiles = ReactiveCommand.Create(() =>
{
var excelApp = new Microsoft.Office.Interop.Excel.Application();
if (excelApp != null)
{
Workbook excelWorkbook = excelApp.Workbooks.Open(@"C:\Users\Mikhail\Desktop\test.xlsx", 0, true,
5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true,
1, 0);
Worksheet excelWorksheet = (Worksheet)excelWorkbook.Sheets[1];
Range excelRange = excelWorksheet.UsedRange;
int rowCount = excelRange.Rows.Count;
int colCount = excelRange.Columns.Count;
for (int i = 1; i <= rowCount; i++)
{
for (int j = 1; j <= colCount; j++)
{
Range range = (excelWorksheet.Cells[i, 1] as Range);
string cellValue = range.Value.ToString();
ElementsList.Add(new ObservableCollection<Elements>
{
new()
{
Id = ElementsList.Count, Text = cellValue
}
});
}
}
excelWorkbook.Close();
excelApp.Quit();
}
});
// using var resource = AssetLoader.Open(new Uri(@"avares://AvaloniaApplication24/Assets/Testing.txt"));
// using var reader = new StreamReader(resource);
}
private async void Mark()
{
var CreateWindow = new MainWindow();
var topLevel = TopLevel.GetTopLevel(CreateWindow);
// Start async operation to open the dialog.
var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = "Open Text File",
AllowMultiple = false
});
if (files.Count >= 1)
{
// Open reading stream from the first file.
await using var stream = await files[0].OpenReadAsync();
using var streamReader = new StreamReader(stream);
// Reads all the content of file as a text.
}
}
}
Model:
public class Elements: ViewModelBase
{
private int _id;
private string _text;
public int Id
{
get => _id;
set => this.RaiseAndSetIfChanged(ref _id, value);
}
public string Text
{
get => _text;
set => this.RaiseAndSetIfChanged(ref _text, value);
}
}
View:
<StackPanel>
<Button Content="add new row" Command="{Binding AddNewRow}" />
<Button Content="Import" Command="{Binding ImportFiles}"></Button>
<ItemsControl ItemsSource="{Binding ElementsList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id}"></TextBlock>
<TextBox Text="{Binding Text}"></TextBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Ответы (2 шт):
У меня получилось ответить на свой вопрос. Но может есть другие способы по импорту файлов? Данный способ выглядит как-то не очень). Также если встречаются пустые ячейки, а после них текст то получаю исключение Object reference not set to an instance of an object. Хотя если ловить исключение то все хорошо.
VM:
public class MainWindowViewModel : ViewModelBase
{
private ObservableCollection<Elements> _elementsList;
public ObservableCollection<Elements> ElementsList
{
get => _elementsList;
set => this.RaiseAndSetIfChanged(ref _elementsList, value);
}
public ReactiveCommand<Unit, Unit> AddNewRow { get; set; }
public ReactiveCommand<Unit, Unit> ImportFiles { get; set; }
public MainWindowViewModel()
{
ElementsList = new ObservableCollection<Elements>(new List<Elements>());
ElementsList.Add(new ObservableCollection<Elements>
{
new()
{
Id = ElementsList.Count, Text = ""
}
});
AddNewRow = ReactiveCommand.Create(() =>
{
ElementsList.Add(new ObservableCollection<Elements>
{
new()
{
Id = ElementsList.Count, Text = ""
}
});
});
ImportFiles = ReactiveCommand.Create(Mark);
}
string _path;
private static FilePickerFileType Excel { get; } = new("All xls")
{
Patterns = new[]
{
"*.xlsx",
"*.xls"
},
MimeTypes = null,
AppleUniformTypeIdentifiers = null,
};
private async void Mark()
{
var topLevel = TopLevel.GetTopLevel(new MainWindow());
// Start async operation to open the dialog.
var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = "Open Excel File",
AllowMultiple = false,
FileTypeFilter = new[] { Excel },
SuggestedStartLocation = await topLevel.StorageProvider.TryGetFolderFromPathAsync("C:\\")
});
if (files.Count >= 1)
{
// Open reading stream from the first file.
await using var stream = await files[0].OpenReadAsync();
using var streamReader = new StreamReader(stream);
// Reads all the content of file as a text.
_path = files[0].Path.LocalPath;
Console.WriteLine(_path);
}
var excelApp = new Microsoft.Office.Interop.Excel.Application();
if (excelApp != null)
{
Workbook excelWorkbook = excelApp.Workbooks.Open(Filename: _path, 0, true,
5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true,
1, 0);
Worksheet excelWorksheet = (Worksheet)excelWorkbook.Sheets[1];
Range excelRange = excelWorksheet.UsedRange;
int rowCount = excelRange.Rows.Count;
int colCount = excelRange.Columns.Count;
for (int i = 1; i <= rowCount; i++)
{
for (int j = 1; j <= colCount; j++)
{
Range range = (excelWorksheet.Cells[i, 1] as Range);
string cellValue = range.Value.ToString();
ElementsList.Add(new ObservableCollection<Elements>
{
new()
{
Id = ElementsList.Count, Text = cellValue
}
});
}
}
excelWorkbook.Close();
excelApp.Quit();
}
}
}
Это не ответ, просто вариант решения (не оптимальный, но рабочий для меня): код для Windows Forms!
//-- запрашиваем файл
using (var ofd = new OpenFileDialog() { Filter = "Файл Excel|*.XLSX;*.XLS;*.XLSM", CheckFileExists = true, CheckPathExists = true, Title = "Открыть импортируемый файл" })
{
if (ofd.ShowDialog() == DialogResult.OK && File.Exists(ofd.FileName))
{
DoImport(ofd.FileName);
}
}
//-- кусок кода DoImport:
/// <summary>
/// Осуществление непосредственного импорта во внутренние структуры программы
/// </summary>
/// <param name="FileName">Имя файла для импорта</param>
public void DoImport(string FileName)
{
//-- получаем экземпляр приложения Excel
//-- Внимание! В следующих 3 х строчках кода недопустимо использовать "var", будет ошибка, только явное задание переменных!
//-- фиг его знает, с чем это связано
Excel.Application app = new Excel.Application();
//-- открываем рабочий файл с диска
Excel.Workbook wrkbook = app.Workbooks.Open(FileName); //, ReadOnly:true);
//-- получаем активную страницу
object sheet = wrkbook.ActiveSheet;
var wrksht = (Excel.Worksheet)sheet;
//-- Считываем первые пять тысяч строк (думается более и не надо, но если что можно и добавить)
object workingRangeCells = wrksht.get_Range("A2:AC5000", Type.Missing);
object arr = ((Excel.Range)workingRangeCells).Cells.Value2;
var array = (Array)arr;
app.Workbooks.Close();
var data = new List<import>();
//-- первую строчку пропускаем, там заголовки, которые нам не требуются
//-- читаем подряд все данные, которые есть в EXCEL
SplashScreenManager.Default.SetWaitFormDescription("Чтение данных...");
Application.DoEvents();
for (var i = 1; i <= 5001; i++)
{
if (array.GetValue(i, 1) == null)
break;
var datv = DateTime.MinValue;
var datu = DateTime.MinValue;
try
{
if (array.GetValue(i, 11) != null)
datv = DateTime.Parse(TextCorrection.CleanTrash(array.GetValue(i, 11).ToString()));
}
catch (Exception)
{
//-- лишний код, и так понятно, что просто подавление ошибки
// Logger.log.Log(Logger.GetErrorInfo(ex));
}
try
{
if (array.GetValue(i, 27) != null)
datu = DateTime.Parse(TextCorrection.CleanTrash(array.GetValue(i, 27).ToString()));
}
catch (Exception)
{
//-- лишний код, и так понятно, что просто подавление ошибки
// Logger.log.Log(Logger.GetErrorInfo(ex));
}
var rec = new import
{
v1 = TextCorrection.CleanNBSPAndTrash(array.GetValue(i, 1).ToString()).Trim(), //-- первая строка всегда проверяется на старте
v2 = array.GetValue(i, 2) != null ? TextCorrection.CleanTrash(array.GetValue(i, 2).ToString()).Trim() : string.Empty,
v3 = array.GetValue(i, 3) != null ? TextCorrection.CleanTrash(array.GetValue(i, 3).ToString()).Trim() : string.Empty,
v4 = array.GetValue(i, 4) != null ? TextCorrection.CleanNBSPAndTrash(array.GetValue(i, 4).ToString()).Trim() : string.Empty,
v5 = array.GetValue(i, 5) != null ? TextCorrection.CleanTrash(array.GetValue(i, 5).ToString()).Trim() : string.Empty,
};
data.Add(rec);
}
#region -- Служебный код завершения работы EXCEL - обнуляем все данные Excel для попытки закрыть запущенный процесс...
//-- на самом деле убить эту гадину не так просто. ну хоть попытаемся...
arr = null;
array = null;
wrksht = null;
sheet = null;
wrkbook = null;
app.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
app = null;
//-- ... не удаляется, но помирает, как только выйти из программы
#endregion