?
Solved

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

Posted on 2016-08-19
6
Medium Priority
?
416 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
6 Comments
 
LVL 34

Expert Comment

by:it_saige
ID: 41763135
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 34

Expert Comment

by:it_saige
ID: 41763149
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
ID: 41764955
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
Quiz: What Do These Organizations Have In Common?

Hint: Their teams ended up taking quizzes, too.

 
LVL 34

Accepted Solution

by:
it_saige earned 2000 total points
ID: 41765672
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
ID: 41766474
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
ID: 41766475
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

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
Suggested Courses

770 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