WPF: Bind to each value of a property generated via reflection in ObservableCollection

I have a large list of objects, we'll call the object SpecialData, with ~60 properties on it. I created a class to represent each property in the UI like so (using MVVM toolkit hence the attributes):
public partial class CheckableProperty : ObservableObject
{
public string DisplayName { get; set; } = string.Empty;
public string PropertyName { get; set; } = string.Empty;

[ObservableProperty]
private bool _isSelected;

[ObservableProperty]
private string _propertyValue = string.Empty;
}
public partial class CheckableProperty : ObservableObject
{
public string DisplayName { get; set; } = string.Empty;
public string PropertyName { get; set; } = string.Empty;

[ObservableProperty]
private bool _isSelected;

[ObservableProperty]
private string _propertyValue = string.Empty;
}
In my viewmodel, I get all the attributes of the SpecialData class and map them to a collection of CheckableProperty objects like so:
ObservableCollection AvailableProperties = new ObservableCollection<CheckableProperty>(
typeof(SpecialData).GetProperties()
.Select(prop => new CheckableProperty
{
DisplayName = ((DisplayNameAttribute?)prop.GetCustomAttributes(typeof(DisplayNameAttribute)).FirstOrDefault())?.DisplayName ?? prop.Name,
PropertyName = prop.Name,
IsSelected = true
}));
ObservableCollection AvailableProperties = new ObservableCollection<CheckableProperty>(
typeof(SpecialData).GetProperties()
.Select(prop => new CheckableProperty
{
DisplayName = ((DisplayNameAttribute?)prop.GetCustomAttributes(typeof(DisplayNameAttribute)).FirstOrDefault())?.DisplayName ?? prop.Name,
PropertyName = prop.Name,
IsSelected = true
}));
Now in the UI, I want to show each property and its corresponding value for whatever my selected item is in the list of SpecialData objects. Right now I am doing this every time I select a different item to show the properties of:
private void UpdateSelectedProperties(SpecialData obj)
{
AvailableProperties = new ObservableCollection<PropertySelection>(
typeof(SpecialData).GetProperties()
.Where(prop => prop.GetCustomAttribute<CsvIgnoreAttribute>() == null && prop.GetSetMethod() != null) // Check for ignore attribute and setter
.Select(prop => new PropertySelection
{
DisplayName = ((DisplayNameAttribute?)prop.GetCustomAttributes(typeof(DisplayNameAttribute)).FirstOrDefault())?.DisplayName ?? prop.Name,
Value = prop.GetValue(obj)?.ToString() ?? ""
}));
}
private void UpdateSelectedProperties(SpecialData obj)
{
AvailableProperties = new ObservableCollection<PropertySelection>(
typeof(SpecialData).GetProperties()
.Where(prop => prop.GetCustomAttribute<CsvIgnoreAttribute>() == null && prop.GetSetMethod() != null) // Check for ignore attribute and setter
.Select(prop => new PropertySelection
{
DisplayName = ((DisplayNameAttribute?)prop.GetCustomAttributes(typeof(DisplayNameAttribute)).FirstOrDefault())?.DisplayName ?? prop.Name,
Value = prop.GetValue(obj)?.ToString() ?? ""
}));
}
6 Replies
Nacho Man Randy Cabbage
What I have doesn't seem like a good way to refresh the data when I change the selected item. Looking for any help to make it better.
Buddy
Buddy10mo ago
Can't you just SG (Source Generator) it? Also faster than reflection
Nacho Man Randy Cabbage
Have never done anything with source generators before, but I'm guessing that would just replace the reflection part? Would I still have to re-create the collection of properties every time I select a new object? Like if I listed out every property by hand in the xaml it would look something like
<Textblock Text="My Property" />
<TextBox Text={Binding SelectedObject.MyProperty" />
<Textblock Text="My Property" />
<TextBox Text={Binding SelectedObject.MyProperty" />
for every property I'd rather use an ItemTemplate and just bind to something to auto-create it all
Buddy
Buddy10mo ago
If you have never messed with source generators before it is quite a learning curve, it requires knowing the internals of Roslyn (compiler). But the best way is using a syntax tree visualizer, which I remember Visual Studio had. And yes, it is just replacing the reflection part. MVVM Toolkit uses source generators, that is why you need to use partial when applying the attributes.
Nacho Man Randy Cabbage
Oh jeez, yeah never really looked into Roslyn related things. Maybe that'll be the next thing I read up on
Want results from more Discord servers?
Add your server