Solved

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

Posted on 2016-08-19
6
102 Views
Last Modified: 2016-09-12
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
0
Comment
Question by:databarracks
  • 3
  • 3
6 Comments
 
LVL 32

Expert Comment

by:it_saige
Comment Utility
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 -Capture.JPG
-saige-
0
 
LVL 32

Expert Comment

by:it_saige
Comment Utility
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-
0
 

Author Comment

by:databarracks
Comment Utility
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.
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 32

Accepted Solution

by:
it_saige earned 500 total points
Comment Utility
The foreach is not type specific, it is dynamic which means that the compiler attempts to *infer* the structure of the passed object.  In vb.net the usage of an ExapandoObject over a DynamicObject was so that we could retain the properties from the original source object which, in all presented examples, is anonymous.

Consider the following, which gives us the same output -
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()

	Sub Main()
		Dim [collection] As New DynamicCollection(people)
		[collection].GetColumnsCollection()
		Console.ReadLine()
	End Sub
End Module

Class DynamicCollection
	Private ReadOnly m_selectedItems As ObservableCollection(Of ExpandoObject)
	Public ReadOnly Property SelectedItems()
		Get
			Return m_selectedItems
		End Get
	End Property

	Public Sub New(source As IEnumerable)
		If source IsNot Nothing Then
			m_selectedItems = New ObservableCollection(Of ExpandoObject)
			For Each item In source
				Dim obj = New ExpandoObject()
				For Each [property] As PropertyInfo In item.GetType().GetProperties()
					CType(obj, IDictionary(Of String, Object)).Add([property].Name, [property].GetValue(item, Nothing))
				Next
				m_selectedItems.Add(obj)
			Next
		End If
	End Sub

	Public 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 Class

Open in new window

-saige-
0
 

Author Comment

by:databarracks
Comment Utility
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!!
0
 

Author Closing Comment

by:databarracks
Comment Utility
it_saige was absolutely on the ball and would like to thank them for their help. First class help and detailed explanations
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now