In WPF there is no built-in way to make a ListView display generic content.  The DataGrid has this ability but is probably too much for just a display.

To this end I have created an AttachedProperty that will allow the user to use a ListView with that ability.  To use this AttachedProperty simply use the following XAML.

<ListView ItemsSource="{Binding theList}" Grid.Row="2"
          local:DynamicBindingListView.GenerateColumnsGridView="True"
          local:DynamicBindingListView.DateFormatString="MM/dd/yyyy">
    <ListView.View>
        <GridView></GridView>
    </ListView.View>
</ListView>

There are actually two AttachedProperties within the DynamicBindingListView.  The first property GenerateColumnsGridView is the main property.  Setting this property will cause the DynamicBindingListView to monitor changes to the ItemsSource of the ListView.  When the ItemsSource is updated the AttachedProperty will scan the items (actually only the first item) of the ItemsSource and using Reflection get the properties of the Objects within the ItemsSource.  If there is more than one object type within the collection it will only deal with the properties from the first object.

The second Attached Property is the DateFormatString.  This allows the user to define the format for any and all dates displayed by using this AttachedProperty.  If it is not defined for the ListView the default display for a date will be used.  This property is actually there as a sample of how the user can define the Format of columns but as I said above there is no way (at present) to format different columns of the same type with different formats.

The code for the DynamicBindingListView object is as follows:  (VB.NET C# to follow later)

VB.NET Version

Imports System.ComponentModel
Imports System.Collections.Specialized
Imports System.Reflection
 
Public Class DynamicBindingListView
 
    Public Shared Function GetGenerateColumnsGridView(ByVal element As DependencyObject) As Boolean
        If element Is Nothing Then
            Throw New ArgumentNullException("element")
        End If
 
        Return element.GetValue(GenerateColumnsGridViewProperty)
    End Function
 
    Public Shared Sub SetGenerateColumnsGridView(ByVal element As DependencyObject, ByVal value As Boolean)
        If element Is Nothing Then
            Throw New ArgumentNullException("element")
        End If
 
        element.SetValue(GenerateColumnsGridViewProperty, value)
    End Sub
 
    Public Shared ReadOnly GenerateColumnsGridViewProperty As  _
                           DependencyProperty = DependencyProperty.RegisterAttached("GenerateColumnsGridView", _
                           GetType(Boolean?), GetType(DynamicBindingListView), _
                           New FrameworkPropertyMetadata(Nothing, AddressOf thePropChanged))
 
 
 
    Public Shared Function GetDateFormatString(ByVal element As DependencyObject) As String
        If element Is Nothing Then
            Throw New ArgumentNullException("element")
        End If
 
        Return element.GetValue(DateFormatStringProperty)
    End Function
 
    Public Shared Sub SetDateFormatString(ByVal element As DependencyObject, ByVal value As String)
        If element Is Nothing Then
            Throw New ArgumentNullException("element")
        End If
 
        element.SetValue(DateFormatStringProperty, value)
    End Sub
 
    Public Shared ReadOnly DateFormatStringProperty As  _
                           DependencyProperty = DependencyProperty.RegisterAttached("DateFormatString", _
                           GetType(String), GetType(DynamicBindingListView), _
                           New FrameworkPropertyMetadata(Nothing))
 
    Public Shared Sub thePropChanged(ByVal obj As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        Dim lv As ListView = CType(obj, ListView)
      Dim descriptor As DependencyPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ListView.ItemsSourceProperty, GetType(ListView))
      descriptor.AddValueChanged(lv, New EventHandler(AddressOf ItemsSourceChanged))
    End Sub
 
    Private Shared Sub ItemsSourceChanged(sender As Object, e As EventArgs)
        Dim lv As ListView = CType(sender, ListView)
        Dim its As IEnumerable = lv.ItemsSource
        Dim itsEnumerator As IEnumerator = its.GetEnumerator
        Dim hasItems As Boolean = itsEnumerator.MoveNext()
        If hasItems Then
            SetUpTheColumns(lv, itsEnumerator.Current)
        End If
    End Sub
 
    Private Shared Sub SetUpTheColumns(theListView As ListView, firstObject As Object)
        Dim theClassProperties As PropertyInfo() = firstObject.GetType().GetProperties()
        Dim gv As GridView = theListView.View
        For Each pi As PropertyInfo In theClassProperties
            Dim columnName As String = pi.Name
            Dim grv As New GridViewColumn With {.Header = columnName}
 
            If pi.PropertyType Is GetType(DateTime) Then
                Dim bnd As New Binding(columnName)
                Dim formatString As String = theListView.GetValue(DateFormatStringProperty)
                If formatString <> String.Empty Then
                    bnd.StringFormat = formatString
                End If
                BindingOperations.SetBinding(grv, TextBlock.TextProperty, bnd)
                grv.DisplayMemberBinding = bnd
            Else
                Dim bnd As New Binding(columnName)
                BindingOperations.SetBinding(grv, TextBlock.TextProperty, bnd)
                grv.DisplayMemberBinding = bnd
            End If
            gv.Columns.Add(grv)
        Next
    End Sub
 
End Class


C# Version

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Reflection;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows;
using System.Collections;
using System.Windows.Data;
 
namespace CSharpVersioon
{
    public class DynamicBindingListView
    {
 
        public static bool GetGenerateColumnsGridView(DependencyObject element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
 
            return (bool)element.GetValue(GenerateColumnsGridViewProperty);
        }
 
        public static void SetGenerateColumnsGridView(DependencyObject element, bool value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
 
            element.SetValue(GenerateColumnsGridViewProperty, value);
        }
 
 
        public static readonly DependencyProperty GenerateColumnsGridViewProperty = DependencyProperty.RegisterAttached("GenerateColumnsGridView", typeof(bool?), typeof(DynamicBindingListView), new FrameworkPropertyMetadata(null, thePropChanged));
 
 
        public static string GetDateFormatString(DependencyObject element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
 
            return (string)element.GetValue(DateFormatStringProperty);
        }
 
        public static void SetDateFormatString(DependencyObject element, string value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
 
            element.SetValue(DateFormatStringProperty, value);
        }
 
 
        public static readonly DependencyProperty DateFormatStringProperty = DependencyProperty.RegisterAttached("DateFormatString", typeof(string), typeof(DynamicBindingListView), new FrameworkPropertyMetadata(null));
        public static void thePropChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            ListView lv = (ListView)obj;
            DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor.FromProperty(ListView.ItemsSourceProperty, typeof(ListView));
            descriptor.AddValueChanged(lv, new EventHandler(ItemsSourceChanged));
        }
 
        private static void ItemsSourceChanged(object sender, EventArgs e)
        {
            ListView lv = (ListView)sender;
            IEnumerable its = lv.ItemsSource;
            IEnumerator itsEnumerator = its.GetEnumerator();
            bool hasItems = itsEnumerator.MoveNext();
            if (hasItems)
            {
                SetUpTheColumns(lv, itsEnumerator.Current);
            }
        }
 
        private static void SetUpTheColumns(ListView theListView, object firstObject)
        {
            PropertyInfo[] theClassProperties = firstObject.GetType().GetProperties();
            GridView gv = (GridView)theListView.View;
            foreach (PropertyInfo pi in theClassProperties)
            {
                string columnName = pi.Name;
                GridViewColumn grv = new GridViewColumn { Header = columnName };
 
                if (object.ReferenceEquals(pi.PropertyType, typeof(DateTime)))
                {
                    Binding bnd = new Binding(columnName);
                    string formatString = (string)theListView.GetValue(DateFormatStringProperty);
                    if (formatString != string.Empty)
                    {
                        bnd.StringFormat = formatString;
                    }
                    BindingOperations.SetBinding(grv, TextBlock.TextProperty, bnd);
                    grv.DisplayMemberBinding = bnd;
                }
                else
                {
                    Binding bnd = new Binding(columnName);
                    BindingOperations.SetBinding(grv, TextBlock.TextProperty, bnd);
                    grv.DisplayMemberBinding = bnd;
                }
                gv.Columns.Add(grv);
            }
        }
 
    }
}

How does it work?

The DynamicBindigListView class holds two AttachedProperties.  The first GenerateColumnsGridView is a boolean but in reality it does not use the value provided in XAML.  This property is used as an initialization of the class and has a method thePropChanged as a method of setting up for generating columns in a ListView/GridView.  The thePropChanged method simply gets a DependencyPropertyDescriptor for the ItemsSource property of the ListView and registers a callback method for when the property is changed (ItemsSourceChanged).

Then when the ItemsSource of the ListView is changed and there are items in the collection it will get the first items and iterate thru the properties.  For each property a GridViewColumn is created with a Header equivalent to the property name.  When testing this code I used only the DisplayMemberBinding but while that works it would not allow either converters or FormatStrings to be used, so the BindingOperations.SetBinding was added to allow that.  I could not find any documentation of why this is so but I went on observed behaviour for this part of the code.

To illustrate how to extend this I added the ability to add a FormatString if the datatype of the property is a DateTime.  The DateFormatString attached property is use to pass this information to the class.  Adding other attached properties could be used to pass other information for use in binding.





 
 I hope this will help anyone who wants to have the same functionality as the DataGrid with respect to automatically generating columns.