Solved

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

Posted on 2016-08-19
6
282 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 33

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 33

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
Guide to Performance: Optimization & Monitoring

Nowadays, monitoring is a mixture of tools, systems, and codes—making it a very complex process. And with this complexity, comes variables for failure. Get DZone’s new Guide to Performance to learn how to proactively find these variables and solve them before a disruption occurs.

 
LVL 33

Accepted Solution

by:
it_saige earned 500 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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
ASP.NET - Why is accordion not working? 3 49
Coding for the first time 9 68
Copying from a network share 3 26
Send parameters via datatable ajax call 4 9
Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Email security requires an ever evolving service that stays up to date with counter-evolving threats. The Email Laundry perform Research and Development to ensure their email security service evolves faster than cyber criminals. We apply our Threat…

749 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