Link to home
Start Free TrialLog in
Avatar of databarracks
databarracks

asked on

How to Get ObservableCollections field or column names using for each C# or VB in WPF

Hi guys,

I am trying to obtain the field names of a dynamic observable collection in a for each loop. The data is created at runtime so a bit trickier to get the property/fieldnames of the collection. I can bind to the field names in my XAML no problem and all works well but I need to get the names of all the fields that have been generated at runtime if possible, because I want to map these fields in an insert statement later in my code.

So I am assuming if I can bind items like below the field name does exist somewhere in the dynamic ObservableCollection:

        <!--<ListBox Grid.Column="1" Grid.Row="1"  Width="400" ItemsSource="{Binding SelectedItems}" Margin="5">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding FirstName}"/>
                        <TextBlock Text="{Binding LastName}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>-->

Open in new window



The current code I have is below which tries to loop through observable collection of which nothing happens:

        
    Private m_selectedItems As ObservableCollection(Of Object)
    Public ReadOnly Property SelectedItems() As ObservableCollection(Of Object)
        Get
            If m_selectedItems Is Nothing Then
                m_selectedItems = New ObservableCollection(Of Object)()
                m_selectedItems.Add(MyTestCollection)
            End If
            Return m_selectedItems
        End Get
    End Property

    Public Sub GetColumnsCollection()

        Dim myType As Type = SelectedItems.[GetType]()

        Dim props As IList(Of FieldInfo) = New List(Of FieldInfo)(myType.GetFields())

        For Each prop As FieldInfo In props
            Console.WriteLine(prop.FieldType.Name)
        Next

    End Sub

Open in new window


Thank you for your help in advance
Avatar of it_saige
it_saige
Flag of United States of America image

Use an ExpandoObject; e.g. -
Imports System.Collections.ObjectModel
Imports System.Dynamic
Imports System.Reflection

Module Module1
	ReadOnly people = (From i In Enumerable.Range(0, 20) Select New With {.ID = i, .FirstName = String.Format("FirstName{0}", i), .MiddleName = String.Format("MiddleName{0}", i), .LastName = String.Format("LastName{0}", i), .Birthdate = DateTime.Now.AddYears(-(9 * i)), .FullName = String.Format("{0} {1}. {2}", .FirstName, .MiddleName.First(), .LastName), .Age = String.Format("{0} years old", .Birthdate.Year - DateTime.Now.Year)}).ToList()

	Private m_selectedItems As ObservableCollection(Of ExpandoObject)
	Public ReadOnly Property SelectedItems() As ObservableCollection(Of ExpandoObject)
		Get
			If m_selectedItems Is Nothing Then
				m_selectedItems = New ObservableCollection(Of ExpandoObject)
				For Each p In people
					Dim obj = New ExpandoObject()
					For Each [property] As PropertyInfo In p.GetType().GetProperties()
						CType(obj, IDictionary(Of String, Object)).Add([property].Name, [property].GetValue(p, Nothing))
					Next
					m_selectedItems.Add(obj)
				Next
			End If
			Return m_selectedItems
		End Get
	End Property

	Sub Main()
		GetColumnsCollection()
		Console.ReadLine()
	End Sub

	Sub GetColumnsCollection()
		If SelectedItems IsNot Nothing AndAlso SelectedItems.Count > 0 Then
			For Each pair In SelectedItems(0)
				Console.WriteLine("Column: {0}; TypeOf: {1}", pair.Key, pair.Value.GetType())
			Next
		End If
	End Sub
End Module

Open in new window


Produces the following output -User generated image
-saige-
Or for C# use dynamic's:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace EE_Q28964322
{
	class Program
	{
		static readonly dynamic people = (from i in Enumerable.Range(0, 20) 
								    let fName = string.Format("FirstName{0}", i)
								    let mName = string.Format("MiddleName{0}", i)
								    let lName = string.Format("LastName{0}", i)
								    let bDate = DateTime.Now.AddYears(-(9 * i))
								    select new
								    { 
									    ID = i, 
									    FirstName = fName, 
									    MiddleName = mName, 
									    LastName = lName, 
									    Birthdate = bDate, 
									    FullName = string.Format("{0} {1}. {2}", fName, mName.First(), lName), 
									    Age = string.Format("{0} years old", bDate.Year - DateTime.Now.Year)
								    });

		static ObservableCollection<dynamic> m_selectedItems;
		static ObservableCollection<dynamic> SelectedItems
		{
			get
			{
				if (m_selectedItems == null)
				{
					m_selectedItems = new ObservableCollection<dynamic>();
					foreach (var p in people)
						m_selectedItems.Add(p);
				}
				return m_selectedItems;
			}
		}

		static void Main(string[] args)
		{
			GetColumnsCollection();
			Console.ReadLine();
		}

		static void GetColumnsCollection()
		{
			if (SelectedItems != null && SelectedItems.Count > 0)
			{
				foreach (var property in SelectedItems[0].GetType().GetProperties())
					Console.WriteLine("Column: {0}; TypeOf: {1}", property.Name, property.GetValue(SelectedItems[0], null).GetType());
			}
		}
	}
}

Open in new window

Alternative GetColumnsCollections:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace EE_Q28964322
{
	class Program
	{
		static readonly dynamic people = (from i in Enumerable.Range(0, 20) 
								    let fName = string.Format("FirstName{0}", i)
								    let mName = string.Format("MiddleName{0}", i)
								    let lName = string.Format("LastName{0}", i)
								    let bDate = DateTime.Now.AddYears(-(9 * i))
								    select new
								    { 
									    ID = i, 
									    FirstName = fName, 
									    MiddleName = mName, 
									    LastName = lName, 
									    Birthdate = bDate, 
									    FullName = string.Format("{0} {1}. {2}", fName, mName.First(), lName), 
									    Age = string.Format("{0} years old", bDate.Year - DateTime.Now.Year)
								    });

		static ObservableCollection<dynamic> m_selectedItems;
		static ObservableCollection<dynamic> SelectedItems
		{
			get
			{
				if (m_selectedItems == null)
				{
					m_selectedItems = new ObservableCollection<dynamic>();
					foreach (var p in people)
						m_selectedItems.Add(p);
				}
				return m_selectedItems;
			}
		}

		static void Main(string[] args)
		{
			GetColumnsCollection();
			Console.ReadLine();
		}

		static void GetColumnsCollection()
		{
			if (SelectedItems != null && SelectedItems.Count > 0)
			{
				foreach (var property in SelectedItems.GetType().GetGenericArguments()[0].GetProperties())
					Console.WriteLine("Column: {0}; TypeOf: {1}", property.Name, property.GetValue(SelectedItems[0], null).GetType());
			}
		}
	}
}

Open in new window


Each produces the same output as above.

-saige-
Avatar of databarracks
databarracks

ASKER

Thanks for the response. I still have an issue with all of your suggestions because of the for each inside selecteditems. The data can come from different sources so I cannot determine the class or object name as a user can chance the datasource at runtime based on their selection.
ASKER CERTIFIED SOLUTION
Avatar of it_saige
it_saige
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ahh I see:) That makes sense and my solution is now working as expected. Thank you so much for helping me out on this.........awesome work!!
it_saige was absolutely on the ball and would like to thank them for their help. First class help and detailed explanations