The DataTable is populated with the data from a database.
var query = $"SELECT * FROM {databaseTable.Name}";
OracleCommand oracleCommand = new OracleCommand(query, _connection);
OracleDataAdapter oracleDataAdapter = new OracleDataAdapter(oracleCommand);
DataTable data = new DataTable();
oracleDataAdapter.Fill(data);
return data;
I want to populate a DataGrid with the DataTable trough Itemssource. We don't want to specify any objects (classes). We want to fill the Grid with only the informations we get from the DataTable
<control:DataGrid x:Name="gridView1" Margin="5" ItemsSource="{Binding DataTable}" GridLinesVisibility="All" AlternatingRowBackground="DarkBlue">
At the moment I have a ListView that shows me all the Tables that we read out separately from the database
<ListView x:Name="listView" ItemsSource="{Binding DatabaseTables, Mode=TwoWay}" DisplayMemberPath="Name" SelectedItem="{Binding DatabaseTable, Mode=TwoWay}">
and by selecting a table we want all the entries shown in the Grid with the expecting columns from the DataTable
I tried to look around, but couldn't find a solution.
This should work:
MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
using System.Data;
using System.Threading.Tasks;
namespace DataTableExample;
// This class needs to be "partial"
// for the CommunityToolkit.NuGet package source generators.
public partial class MainPageViewModel : ObservableObject
{
[ObservableProperty]
// "Items" property will be auto-generated for you.
private ObservableCollection<object>? _items;
[RelayCommand]
// "LoadItemsCommand" will be auto-generated for you.
private async Task LoadItems()
{
DataTable dataTable = await LoadItemsFromDataBase();
ObservableCollection<object> items = new();
foreach (DataRow row in dataTable.Rows)
{
items.Add(row.ItemArray);
}
Items = items;
}
private Task<DataTable> LoadItemsFromDataBase()
{
return Task.Run(() =>
{
DataTable dataTable = new();
dataTable.Columns.Add("Id", typeof(int));
dataTable.Columns.Add("Name", typeof(string));
dataTable.Columns.Add("Price", typeof(decimal));
dataTable.Rows.Add(1, "Product 1", 10.0);
dataTable.Rows.Add(2, "Product 2", 20.0);
dataTable.Rows.Add(3, "Product 3", 30.0);
return dataTable;
});
}
}
MainPage.xaml.cs
using Microsoft.UI.Xaml.Controls;
namespace DataTableExample;
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private MainPageViewModel ViewModel => new();
}
MainPage.xaml
<Page
x:Class="DataTableExample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:DataTableExample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="using:CommunityToolkit.WinUI.UI.Controls"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid RowDefinitions="Auto,*">
<Button
Grid.Row="0"
Command="{x:Bind ViewModel.LoadItemsCommand}"
Content="Load items" />
<toolkit:DataGrid
Grid.Row="1"
AutoGenerateColumns="False"
ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}">
<toolkit:DataGrid.Columns>
<toolkit:DataGridTextColumn
Binding="{Binding [0]}"
Header="ID" />
<toolkit:DataGridTextColumn
Binding="{Binding [1]}"
Header="Name" />
<toolkit:DataGridTextColumn
Binding="{Binding [2]}"
Header="Price" />
</toolkit:DataGrid.Columns>
</toolkit:DataGrid>
</Grid>
</Page>
NOTE:
I'm using the CommunityToolkit.Mvvm NuGet package for the MVVM design.
UPDATE:
I came up with another solution that might be a bit closer to your requirements. This way you won't need to declare each column in XAML.
DataGridExtensions.cs
using CommunityToolkit.WinUI.UI.Controls;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using System.Collections.ObjectModel;
namespace DataTableExample;
public static class DataGridExtensions
{
public static readonly DependencyProperty ColumnsProperty =
DependencyProperty.RegisterAttached(
"Columns",
typeof(ObservableCollection<Column>),
typeof(DataGridExtensions),
new PropertyMetadata(
new ObservableCollection<Column>(),
OnColumnsPropertyChanged));
public static ObservableCollection<Column> GetColumns(DependencyObject obj)
{
return (ObservableCollection<Column>)obj.GetValue(ColumnsProperty);
}
public static void SetColumns(DependencyObject obj, ObservableCollection<Column> value)
{
obj.SetValue(ColumnsProperty, value);
}
private static void OnColumnsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not DataGrid dataGrid ||
e.NewValue is not ObservableCollection<Column> columns)
{
return;
}
dataGrid.Columns.Clear();
foreach (Column column in columns)
{
Binding binding = new()
{
Path = new PropertyPath(column.Binding)
};
dataGrid.Columns.Add(
new DataGridTextColumn
{
Header = column.Header,
Binding = binding,
});
}
}
public class Column
{
public string? Header { get; set; }
public string? Binding { get; set; }
}
}
MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
using System.Data;
using System.Threading.Tasks;
namespace DataTableExample;
public partial class MainPageViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<object>? _items;
[ObservableProperty]
private ObservableCollection<DataGridExtensions.Column>? _columns;
[RelayCommand]
private async Task LoadItems()
{
DataTable dataTable = await LoadItemsFromDataBase();
ObservableCollection<DataGridExtensions.Column> columns = new();
ObservableCollection<object> items = new();
int index = 0;
foreach (DataColumn column in dataTable.Columns)
{
columns.Add(
new DataGridExtensions.Column {
Header = column.ColumnName,
Binding = $"[{index++}]"
});
}
foreach (DataRow row in dataTable.Rows)
{
items.Add(row.ItemArray);
}
Columns = columns;
Items = items;
}
private Task<DataTable> LoadItemsFromDataBase()
{
return Task.Run(() =>
{
DataTable dataTable = new();
dataTable.Columns.Add("Id", typeof(int));
dataTable.Columns.Add("Name", typeof(string));
dataTable.Columns.Add("Price", typeof(decimal));
dataTable.Rows.Add(1, "Product 1", 10.0);
dataTable.Rows.Add(2, "Product 2", 20.0);
dataTable.Rows.Add(3, "Product 3", 30.0);
return dataTable;
});
}
}
and...
MainPage.xaml
<Page
x:Class="DataTableExample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:DataTableExample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="using:CommunityToolkit.WinUI.UI.Controls"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid RowDefinitions="Auto,*">
<Button
Grid.Row="0"
Command="{x:Bind ViewModel.LoadItemsCommand}"
Content="Load items" />
<toolkit:DataGrid
Grid.Row="1"
local:DataGridExtensions.Columns="{x:Bind ViewModel.Columns, Mode=OneWay}"
AutoGenerateColumns="False"
ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}" />
</Grid>
</Page>