I'm new to c# and trying to inport a XML file into DataGrid but so far I managed to import only the columns header but not the data inside the nodes. I will not know at runtime what kind of data will be loaded from the xml it can be anything but the example below is the overall structure that everything follows.
I have tried looking for answers for my problem but everything I get is for DataGridView which I am not using here so all the searches came up with more information about that than what I am looking to do. Any help will be greatly appriciated. The depth of the tags can very from 1 to 40 or more.
My XMLdata looks like this:
<Details>
<Record>
<Username>name</Username>
<FirstName>firstname</FirstName>
<LastName>lastname</LastName>
etc
.
.
.
</Record>
</Details>
My Xaml
<DataGrid x:Name="DetailsGridTemplate" AlternatingRowBackground="AliceBlue" CanUserAddRows="True" CanUserDeleteRows="True"
ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Visible"
Height="380" Width="430" AutoGenerateColumns="False" IsReadOnly="True" Grid.ColumnSpan="2" Margin="0,0,0.4,0"
ItemsSource="{Binding}">
</DataGrid>
My import code
private void InitGridFromXML(string xmlPath)
{
var data = XElement.Load(xmlPath);
// Set Grid data to row nodes (NOTE: grid = DataGrid member)
var elements = data.Elements("Item");
DetailsGridTemplate.ItemsSource = elements;
// Create grid columns from node attributes. A hashtable ensures
// only one column per attribute since this iterates through all
// attributes in all nodes. This way, the grid can handle nodes with
// mutually different attribute sets.
var cols = new Hashtable();
var rows = new Hashtable();
foreach (XElement node in data.Descendants("Item"))
{
foreach (XElement childNode in node.Descendants())
{
var col = childNode.Name.LocalName;
var row = childNode.Value;
// Only add col if it wasn't added before
if (!cols.Contains(col))
{
// Mark col as added
cols[col] = true;
rows[row] = true;
// Add a column with the title of the attribute and bind to its
// value
DetailsGridTemplate.Columns.Add(new DataGridTextColumn
{
Header = col,
});
DetailsGridTemplate.Items.Add(new DataGridRow
{
DataContext = row,
});
}
}
}
}
Easiest is to use LINQ to XML . You can bind an XElement
directly to an ItemsSource
.
ViewModel.cs
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
this.DataTable = new DataTable();
}
private void InitGridFromXML(string xmlPath)
{
var xmlEntities = XElement.Load(xmlPath).Elements().ToList();
var dataTable = new DataTable();
dataTable.Columns.AddRange(
xmlEntities
.FirstOrDefault()?
.Elements()
.Select(node => new DataColumn(node.Name.LocalName))
.ToArray());
foreach (XElement xElement in xmlEntities)
{
dataTable.Rows.Add(
xElement.Elements()
.Select(node => node.Value)
.ToArray());
}
this.DataTable = dataTable;
}
private DataTable dataTable;
public DataTable DataTable
{
get => this.dataTable;
set
{
this.dataTable = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<Grid>
<DataGrid AutoGenerateColumns="True"
ItemsSource="{Binding DataTable}" />
<Grid>
<Window>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.