How to avoid typing FieldLayout XAML

Here's a trick that was inspired by a recent question in a forum post.  XamDataGrid will automatically create FieldLayouts and Fields for you, based on the type of data source you give it.  If you want to customize the layouts or fields, you can do so by creating those objects in XAML (or code) and configuring their properties.  The downside is that you have to manually type that XAML, which can be time consuming.  In this post, I'll show how you can easily leverage XamDataGrid's automatic field generation capabilities in such a way that you don't have to type in all that boilerplate XAML.

The idea is to let the data grid create the FieldLayouts and Fields, and in a handler for the FieldLayoutInitialized event you create some XAML on-the-fly.  That XAML can then be written to a file, or to the Windows clipboard, or even to the Output window in Visual Studio.  For example, suppose that this is my XAML file:

 <Window
  x:Class="XamDataGridTest.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:igDP="http://infragistics.com/DataPresenter"
  Title="XamDataGrid Test"
  Width="640" Height="480"
  >
  <Grid>
    <igDP:XamDataGrid DataSource="{Binding}" x:Name="xamDG" />
  </Grid>
</Window>

 Here is the code-behind file for that window:

using System.Diagnostics;
using System.Text;
using System.Windows;
using Infragistics.Windows.DataPresenter;
using Infragistics.Windows.DataPresenter.Events;

namespace XamDataGridTest
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            base.DataContext = Task.Create();
            this.xamDG.FieldLayoutInitialized += this.xamDG_FieldLayoutInitialized;
        }

        void xamDG_FieldLayoutInitialized(object sender, FieldLayoutInitializedEventArgs e)
        {
            string xaml = GetXamlForFieldLayout(e.FieldLayout);
            Debug.WriteLine(xaml);
        }

        static string GetXamlForFieldLayout(FieldLayout fieldLayout)
        {
            StringBuilder buffer = new StringBuilder();

            buffer.AppendLine("<igDP:FieldLayout>");
            buffer.AppendLine("  <igDP:FieldLayout.Fields>");

            foreach (Field field in fieldLayout.Fields)
            {
                if (field.IsExpandableResolved == false)
                {
                    buffer.AppendFormat("    <igDP:Field Name=\"{0}\" />", field.Name);
                    buffer.AppendLine();
                }
            }

            buffer.AppendLine("  </igDP:FieldLayout.Fields>");
            buffer.Append("</igDP:FieldLayout>");

            return buffer.ToString();
        }
    }
}

I suppose a more "robust" solution would be to use either an XmlTextWriter, or some XLinq, here.  But, for this simple demo, I'm just using plain string concatenations.

When I run the application by pressing F5 (i.e. in Debug mode), the following XAML is sent to the Output window:

<igDP:FieldLayout>
  <igDP:FieldLayout.Fields>
    <igDP:Field Name="ID" />
    <igDP:Field Name="Name" />
    <igDP:Field Name="PriorityLevel" />
    <igDP:Field Name="State" />
  </igDP:FieldLayout.Fields>
</igDP:FieldLayout>

Each of those Fields corresponds to a property on the Task class in my application.  My data source is hierarchical.  The Task class has a property called Notes, which is an array of TaskNote objects.  The first time I expand one of the records, the FieldLayout used to display a TaskNote object is initialized.  That causes the following XAML to be sent to the Output window:

 <igDP:FieldLayout>
  <igDP:FieldLayout.Fields>
    <igDP:Field Name="CreatedOn" />
    <igDP:Field Name="Notes" />
  </igDP:FieldLayout.Fields>
</igDP:FieldLayout>

Now I can copy and paste that XAML into my Window's XAML file, adjust the FieldLayouts and Fields as I see fit, and then remove the FieldLayoutInitialized handler so that this design-time code does not run in the production application.  The resulting XAML file, after I apply some changes to the Fields, looks like this:

<Window
  x:Class="XamDataGridTest.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:igDP="http://infragistics.com/DataPresenter"
  Title="XamDataGrid Test"
  Width="640" Height="480"
  >
  <Grid>
    <igDP:XamDataGrid DataSource="{Binding}" x:Name="xamDG">
      <igDP:XamDataGrid.FieldLayouts>


        <igDP:FieldLayout>
          <igDP:FieldLayout.Fields>
            <igDP:Field Name="ID" Visibility="Collapsed" />
            <igDP:Field Name="Name" Label="task name" />
            <igDP:Field Name="PriorityLevel" Label="priority level" />
            <igDP:Field Name="State" Label="status" />
          </igDP:FieldLayout.Fields>
        </igDP:FieldLayout>


        <igDP:FieldLayout>
          <igDP:FieldLayout.Fields>         
            <igDP:Field Name="CreatedOn" Label="created"  />
            <igDP:Field Name="Notes" Label="notes..." />           
          </igDP:FieldLayout.Fields>
        </igDP:FieldLayout>


      </igDP:XamDataGrid.FieldLayouts>
    </igDP:XamDataGrid>
  </Grid>
</Window>

Hopefully this trick will shave some time off your development efforts involving XamDataGrid.  Happy coding!


Comments  (2 )

Glenn Long
on Tue, Apr 7 2009 11:20 PM

Josh,

This small piece of code solves so many issues. One of the best I've seen on this site. Bad spellings, names of nested heierarchial data columns, key columns  you name it.

I was having big issues attaching layouts to data sets. This one post solved them all.

Thanks,

Glenn

vrTagore
on Wed, Aug 26 2009 8:34 AM

can you clear this piece of code

base.DataContext = Task.Create();

what is this Task class?

Add a Comment

Please Login or Register to add a comment.