Use Office File API to Import Data from Excel
- 6 minutes to read
This document explains how to use Office File API (in particular, Spreadsheet Document API) to import data from an XLSX file to a DataGridView.
Create a .NET MAUI App
Follow the instructions in the following section to create an app with our .NET MAUI components: Get Started.
Note that the DevExpress library for .NET MAUI targets only Android and iOS platforms (See also: Supported Platforms).
Add Office File API NuGet Packages
Install the following NuGet packages to use Spreadsheet Document API in your app:
See also: Use Office File API in .NET MAUI Applications (macOS, iOS, Android).
Copy Files to App Data Directory
Add a XLSX file (Financial.xlsx in this example) to Resources/Raw folder. Then, copy this file from the application bundle to the app’s data folder to access it from code.
namespace MauiOFAExcelImport {
public partial class MainPage : ContentPage {
public MainPage() {
InitializeComponent();
}
private async void OnLoaded(object sender, EventArgs e) {
await InitFilesAsync("Financial.xlsx");
}
async Task InitFilesAsync(string fileName) {
using Stream fileStream = await FileSystem.Current.OpenAppPackageFileAsync(fileName);
string targetFile = Path.Combine(FileSystem.Current.AppDataDirectory, fileName);
using FileStream outputStream = File.OpenWrite(targetFile);
fileStream.CopyTo(outputStream);
}
}
}
For more information, refer to the following help page: File system helpers.
Implement a ViewModel
In this step, you implement a ViewModel that loads data from an XLSX file to an IEnumerable<FinancialData> collection.
This tutorial uses MVVM Toolkit features to build a View Model. To use this library in your app, install the CommunityToolkit.Mvvm
NuGet package.
The list below includes the main MVVM toolkit features used in this tutorial:
- ObservableObject class - Implements INotifyPropertyChanged and INotifyPropertyChanging interfaces that their descendants use for property change notifications.
- ObservableProperty attribute - Allows generating observable properties from annotated fields.
- RelayCommand attribute - Allows generating relay command properties for annotated methods.
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DevExpress.Spreadsheet;
namespace MauiOFAExcelImport;
public partial class ViewModel : ObservableObject {
[ObservableProperty]
private IEnumerable<FinancialData> finData;
[RelayCommand]
async Task LoadFromExcel() {
Workbook workbook = await WorkbookFromFile("Financial.xlsx");
await AssignListFromWorkbook(workbook);
}
// See the sections below for implementation details of above methods.
}
public class FinancialData
{
public string Ticker { get; set; }
public double Volume { get; set; }
public double BuyValue { get; set; }
public double SellValue { get; set; }
}
Obtain a Workbook from the XLSX File
Create a Workbook object and call the asynchronous LoadDocumentAsync method to load an XLSX file for further processing.
//...
public partial class ViewModel : ObservableObject {
[RelayCommand]
async Task LoadFromExcel() {
Workbook workbook = await WorkbookFromFile("Financial.xlsx");
//...
}
async Task<Workbook> WorkbookFromFile(string fileName) {
Workbook workbook = new Workbook();
string workingFilePath = Path.Combine(FileSystem.Current.AppDataDirectory, fileName);
await workbook.LoadDocumentAsync(workingFilePath, DocumentFormat.Xlsx);
return workbook;
}
}
Load Data from the XLSX File
In this step, you load data from an XLSX file to a list of data objects (each object contains a single worksheet row’s data). The main idea is to iterate through the worksheet cells and save data to a corresponding data object property:
- Use the Worksheets property to access the collection of available worksheets. To access a specific worksheet (Current_Assets in this example), you can use the indexer operator.
- Call the GetDataRange() method to obtain all non-empty worksheet cells.
- Iterate through the collection of obtained cells to copy cell values to the list of data objects. In the following step, this list is used to populate DataGridView columns with data.
public partial class ViewModel : ObservableObject {
[RelayCommand]
async Task LoadFromExcel() {
//...
await AssignListFromWorkbook(workbook);
}
async Task AssignListFromWorkbook(Workbook workbook) {
Worksheet worksheet = workbook.Worksheets["Current_Assets"];
CellRange valuesRange = worksheet.GetDataRange();
int topRowIndex = valuesRange.TopRowIndex;
int leftColumnIndex = valuesRange.LeftColumnIndex + 1; // To start from the second column
if (!IsValidDataStructure(worksheet, topRowIndex, leftColumnIndex)) {
await Shell.Current.DisplayAlert("Error", "Data structure in the selected file is invalid", "OK");
return;
}
List<FinancialData> finDataList = new List<FinancialData>();
for (int rowIndex = topRowIndex + 1; rowIndex < valuesRange.RowCount + topRowIndex; rowIndex++) {
FinancialData newFinDataRecord = new FinancialData() {
Ticker = worksheet.Rows[rowIndex][leftColumnIndex].Value.TextValue,
Volume = worksheet.Rows[rowIndex][leftColumnIndex + 1].Value.NumericValue,
BuyValue = worksheet.Rows[rowIndex][leftColumnIndex + 2].Value.NumericValue,
SellValue = worksheet.Rows[rowIndex][leftColumnIndex + 3].Value.NumericValue,
};
finDataList.Add(newFinDataRecord);
}
FinData = finDataList;
}
bool IsValidDataStructure(Worksheet workSheet, int topRowIndex, int leftColumnIndex) {
return workSheet.Rows[topRowIndex][leftColumnIndex].Value.TextValue == "Ticker" &&
workSheet.Rows[topRowIndex][leftColumnIndex + 1].Value.TextValue == "Volume" &&
workSheet.Rows[topRowIndex][leftColumnIndex + 2].Value.TextValue == "BuyValue" &&
workSheet.Rows[topRowIndex][leftColumnIndex + 3].Value.TextValue == "SellValue";
}
}
Implement a View
In this tutorial, data loaded from the XLXS file is displayed in a data grid. To do so, follow the steps below:
- Initialize the
ContentPage.BindingContext
property with a ViewModel instance. - Add a DataGridView
- Bind the DataGridView’s ItemsSource to the ViewModel’s
FinData
property. - Add columns to the DataGridView’s Columns. Specify the FieldName property for each column to define the data object property that stores column data.
<ContentPage ..
xmlns:dx="http://schemas.devexpress.com/maui"
xmlns:local="clr-namespace:MauiOFAExcelImport"
x:DataType="local:ViewModel"
Loaded="OnLoaded">
<ContentPage.BindingContext>
<local:ViewModel/>
</ContentPage.BindingContext>
<Grid RowDefinitions="50,*">
<Button Command="{Binding LoadFromExcelCommand}"
Text="Load from Excel"/>
<dx:DataGridView ItemsSource="{Binding FinData}"
Grid.Row="1">
<dx:DataGridView.Columns>
<dx:TextColumn FieldName="Ticker"/>
<dx:NumberColumn FieldName="Volume"/>
<dx:NumberColumn FieldName="BuyValue"/>
<dx:NumberColumn FieldName="SellValue"/>
</dx:DataGridView.Columns>
</dx:DataGridView>
</Grid>
</ContentPage>
Results
The code snippets below contain the complete code mentioned in the previous sections:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:dx="http://schemas.devexpress.com/maui"
xmlns:ios="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;assembly=Microsoft.Maui.Controls"
ios:Page.UseSafeArea="true"
x:Class="MauiOFAExcelImport.MainPage"
xmlns:local="clr-namespace:MauiOFAExcelImport"
x:DataType="local:ViewModel"
Loaded="OnLoaded">
<ContentPage.BindingContext>
<local:ViewModel/>
</ContentPage.BindingContext>
<Grid RowDefinitions="50,*">
<Button Command="{Binding LoadFromExcelCommand}"
Text="Load from Excel"/>
<dx:DataGridView ItemsSource="{Binding FinData}"
Grid.Row="1">
<dx:DataGridView.Columns>
<dx:TextColumn FieldName="Ticker"/>
<dx:NumberColumn FieldName="Volume"/>
<dx:NumberColumn FieldName="BuyValue"/>
<dx:NumberColumn FieldName="SellValue"/>
</dx:DataGridView.Columns>
</dx:DataGridView>
</Grid>
</ContentPage>
namespace MauiOFAExcelImport {
public partial class MainPage : ContentPage {
public MainPage() {
InitializeComponent();
}
private async void OnLoaded(object sender, EventArgs e) {
await InitFilesAsync("Financial.xlsx");
}
async Task InitFilesAsync(string fileName) {
using Stream fileStream = await FileSystem.Current.OpenAppPackageFileAsync(fileName);
string targetFile = Path.Combine(FileSystem.Current.AppDataDirectory, fileName);
using FileStream outputStream = File.OpenWrite(targetFile);
fileStream.CopyTo(outputStream);
}
}
}
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DevExpress.Spreadsheet;
namespace MauiOFAExcelImport;
public partial class ViewModel : ObservableObject {
[ObservableProperty]
private IEnumerable<FinancialData> finData;
[RelayCommand]
async Task LoadFromExcel() {
Workbook workbook = await WorkbookFromFile("Financial.xlsx");
await AssignListFromWorkbook(workbook);
}
async Task<Workbook> WorkbookFromFile(string fileName) {
Workbook workbook = new Workbook();
string workingFilePath = Path.Combine(FileSystem.Current.AppDataDirectory, fileName);
await workbook.LoadDocumentAsync(workingFilePath, DocumentFormat.Xlsx);
return workbook;
}
async Task AssignListFromWorkbook(Workbook workbook) {
Worksheet worksheet = workbook.Worksheets["Current_Assets"];
CellRange valuesRange = worksheet.GetDataRange();
int topRowIndex = valuesRange.TopRowIndex;
int leftColumnIndex = valuesRange.LeftColumnIndex + 1; // To start from the second column
if (!IsValidDataStructure(worksheet, topRowIndex, leftColumnIndex)) {
await Shell.Current.DisplayAlert("Error", "Data structure in the selected file is invalid", "OK");
return;
}
List<FinancialData> finDataList = new List<FinancialData>();
for (int rowIndex = topRowIndex + 1; rowIndex < valuesRange.RowCount + topRowIndex; rowIndex++) {
FinancialData newFinDataRecord = new FinancialData() {
Ticker = worksheet.Rows[rowIndex][leftColumnIndex].Value.TextValue,
Volume = worksheet.Rows[rowIndex][leftColumnIndex + 1].Value.NumericValue,
BuyValue = worksheet.Rows[rowIndex][leftColumnIndex + 2].Value.NumericValue,
SellValue = worksheet.Rows[rowIndex][leftColumnIndex + 3].Value.NumericValue,
};
finDataList.Add(newFinDataRecord);
}
FinData = finDataList;
}
bool IsValidDataStructure(Worksheet workSheet, int topRowIndex, int leftColumnIndex) {
return workSheet.Rows[topRowIndex][leftColumnIndex].Value.TextValue == "Ticker" &&
workSheet.Rows[topRowIndex][leftColumnIndex + 1].Value.TextValue == "Volume" &&
workSheet.Rows[topRowIndex][leftColumnIndex + 2].Value.TextValue == "BuyValue" &&
workSheet.Rows[topRowIndex][leftColumnIndex + 3].Value.TextValue == "SellValue";
}
}
public class FinancialData {
public string Ticker { get; set; }
public double Volume { get; set; }
public double BuyValue { get; set; }
public double SellValue { get; set; }
}
Export Grid Data to an XLSX File
The DataGridView component allows you to export its data to different formats, including XLSX, out of box.
For more information, refer to the following help topic: DevExpress .NET MAUI DataGrid - Export Data.