2

I have an ItemsControl that should display the values of some properties of an object.

The ItemsSource of the ItemsControl is an object with two properties: Instance and PropertyName.

What I am trying to do is displaying all the property values of the Instance object, but I do not find a way to set the Path of the binding to the PropertyName value:

<ItemsControl ItemsSource={Binding Path=InstanceProperties}> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Path=PropertyName, Mode=OneWay}"/> <TextBlock Text=": "/> <TextBlock Text="{Binding Source=??{Binding Path=Instance}??, Path=??PropertyName??, Mode=OneWay}"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 

the question marks are the points where I don't know how to create the binding.

I initially tried with a MultiValueConverter:

<TextBlock Grid.Column="1" Text="{Binding}"> <TextBlock.DataContext> <MultiBinding Converter="{StaticResource getPropertyValue}"> <Binding Path="Instance" Mode="OneWay"/> <Binding Path="PropertyName" Mode="OneWay"/> </MultiBinding> </TextBlock.DataContext> </TextBlock> 

The MultiValueConverter uses Reflection to look through the Instance and returns the value of the property.

But if the property value changes, this change is not notified and the displayed value remains unchanged.

I am looking for a way to do it with XAML only, if possible, if not I will have to write a wrapper class to for the items of the ItemsSource collection, and I know how to do it, but, since it will be a recurring task in my project, it will be quite expensive.

Edit:

For those who asked, InstanceProperties is a property on the ViewModel which exposes a collection of objects like this:

public class InstanceProperty : INotifyPropertyChanged { //[.... INotifyPropertyChanged implementation ....] public INotifyPropertyChanged Instance { get; set; } public string PropertyName { get; set; } } 

Obviously the two properties notify theirs value is changing through INotifyPropertyChanged, I don't include the OnPropertyChanged event handling for simplicity.

The collection is populated with a limited set of properties which I must present to the user, and I can't use a PropertyGrid because I need to filter the properties that I have to show, and these properties must be presented in a graphically richer way.

Thanks

5
  • 2
    Please show the ViewModel/CodeBehind to let us see, how your datastructure is Commented Jul 4, 2016 at 10:59
  • 2
    I cannot think of any way to dynamically iterate and bind to an arbitrary object's properties in XAML only. You need to write a VM or behaviour to do this so you can watch for change notifications, but do it in a generic way using reflection you can just reuse it throughout your project. Commented Jul 4, 2016 at 11:09
  • 4
    You aren't looking for a PropertyGrid? Commented Jul 4, 2016 at 11:35
  • I edited the post to provide the informations you asked, thanks for the comments btw Commented Jul 4, 2016 at 12:31
  • @GazTheDestroyer thanks for the advice, I can modify the InstanceProperty class to provide also a "Value" property and receive value changes notification through INotifyPropertyChanged, if you would like to answer I can mark your post as accepted answer Commented Jul 4, 2016 at 12:35

1 Answer 1

2

Ok, thanks to @GazTheDestroyer comment:

@GazTheDestroyer wrote: I cannot think of any way to dynamically iterate and bind to an arbitrary object's properties in XAML only. You need to write a VM or behaviour to do this so you can watch for change notifications, but do it in a generic way using reflection you can just reuse it throughout your project

I found a solution: editing the ViewModel class InstanceProperty like this

  1. added a PropertyValue property
  2. listen to PropertyChanged event on Instance and when the PropertyName value changed is fired, raise PropertyChanged on PropertyValue
  3. When Instance or PropertyName changes, save a reference to Reflection's PropertyInfo that will be used by PropertyValue to read the value

here is the new, complete, ViewModel class:

public class InstanceProperty : INotifyPropertyChanged { #region Properties and events public event PropertyChangedEventHandler PropertyChanged; private INotifyPropertyChanged FInstance = null; public INotifyPropertyChanged Instance { get { return this.FInstance; } set { if (this.FInstance != null) this.FInstance.PropertyChanged -= Instance_PropertyChanged; this.FInstance = value; if (this.FInstance != null) this.FInstance.PropertyChanged += Instance_PropertyChanged; this.CheckProperty(); } } private string FPropertyName = null; public string PropertyName { get { return this.FPropertyName; } set { this.FPropertyName = value; this.CheckProperty(); } } private System.Reflection.PropertyInfo Property = null; public object PropertyValue { get { return this.Property?.GetValue(this.Instance, null); } } #endregion #region Private methods private void CheckProperty() { if (this.Instance == null || string.IsNullOrEmpty(this.PropertyName)) { this.Property = null; } else { this.Property = this.Instance.GetType().GetProperty(this.PropertyName); } this.RaisePropertyChanged(nameof(PropertyValue)); } private void Instance_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == this.PropertyName) { this.RaisePropertyChanged(nameof(PropertyValue)); } } private void RaisePropertyChanged(string propertyname) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname)); } #endregion } 

and here is the XAML:

<ItemsControl ItemsSource={Binding Path=InstanceProperties}> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Path=PropertyName, Mode=OneWay}"/> <TextBlock Text=": "/> <TextBlock Text="{Binding Path=PropertyValue, Mode=OneWay}"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.