4

I've been trying to bind XML (via an XElement) to a DataGrid dynamically in Silverlight (specifically Silverlight 4, but any solutions in SL3 would be fine too) but have been unable to do so. I hope to do this dynamically (ie - no rigid business objects to represent the XML).

What I'm hoping for in the end is a way to bind to any XElement containing arbitrary XML, and then use some sort of IConverter to transform the XElement into something the DataGrid can bind to - and just "know" how to auto-generate columns and rows from the converted object.

<sdk:DataGrid 
    ItemsSource="{Binding Source={StaticResource MyViewModel}, 
    Path=MyXElement, Converter={SomeConverter}}" AutoGenerateColumns="True">

If possible, I'd like to be able to utilize some sort of reusable declarative component (trying to avoid code-behind on actual Views).

I've tried using DynamicObjects, but the DataGrid can't figure out its properties.

2 Answers 2

2

Below is another alternative that may also help. It's a bit of a hack.

It's written and tested using Silverlight 3.

The ViewModel:

namespace DatagridXml
{
    public class TestViewModel
    {
        public TestViewModel()
        {
            XmlData = @"<people><person><name>Name1</name><age>21</age><address>Address1</address></person><person><name>Name2</name><age>22</age><address>Address2</address></person><person><name>Name3</name><age>23</age><address>Address3</address></person></people>";
        }
        public string XmlData { get; set; }
    }
}

The value converter:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Data;
using System.Xml.Linq;

namespace DatagridXml
{
    public class XmlColumnConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string elementToGenerate = parameter.ToString();
            DataGrid control = value as DataGrid;
            control.Columns.Clear();

            var result = new List<IList<string>>();
            XDocument xmlDoc = XDocument.Parse(control.DataContext.ToString());

            // Generate Columns
            var columnNames = xmlDoc.Descendants(elementToGenerate).FirstOrDefault();
            int pos = 0;
            foreach (var columnName in columnNames.Elements())
            {
                var column = new DataGridTextColumn();
                column.Header = columnName.Name;
                column.Binding = new Binding("[" + pos + "]");
                control.Columns.Add(column);
                pos++;
            }

            // Parse elements to generate column's data
            foreach (var element in xmlDoc.Descendants(elementToGenerate))
            {
                var row = new List<string>();
                foreach (var column in element.Elements())
                {
                    row.Add(column.Value);
                }
                result.Add(row);
            }
            return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("Cannot convert to xml from list.");
        }
    }
}

And, you use like this:

<UserControl
    x:Class="DatagridXml.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
    xmlns:local="clr-namespace:DatagridXml"
    mc:Ignorable="d"
    d:DesignWidth="640"
    d:DesignHeight="480">
    <UserControl.Resources>
        <local:XmlColumnConverter
            x:Key="XmlColumnConverter" />
        <local:TestViewModel
            x:Key="TestViewModel" />
    </UserControl.Resources>
    <Grid
        x:Name="LayoutRoot">
        <data:DataGrid
            AutoGenerateColumns="False"
            DataContext="{Binding Source={StaticResource TestViewModel}, Path=XmlData}"
            ItemsSource="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource XmlColumnConverter}, ConverterParameter=person}" />
    </Grid>
</UserControl>
Sign up to request clarification or add additional context in comments.

Comments

0

Take a look on the following link. It may be a good start: http://www.scottlogic.co.uk/blog/colin/2010/03/binding-a-silverlight-3-datagrid-to-dynamic-data-via-idictionary-updated/

1 Comment

i was hoping for something that would dynamically figure out the data structure, since my XML won't explicitly layout the structure in rows and columns.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.