I am trying to make a page to display and edit the details on a subject. Depending on the type of subject, we want to display different fields to the user. Some subject types need to display a barcode field, some needs a Tutor name, etc etc.
Some may have a total of 5-6 fields, another one can have 12 fields to display, and this is all configurable, so my page has to be dynamic, I cannot have anything hardcoded.
What I did so far is that I created this ItemsControl on my page (which is a UserControl):
<!-- Subject Info section -->
<Grid Grid.Row="2" Grid.Column="0">
<ItemsControl ItemsSource="{Binding SubjectDataFields}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" />
<TextBox Grid.Column="1">
<TextBox.Text>
<MultiBinding Converter="{StaticResource SubjectFieldValueConverter}">
<Binding Path="DataContext.Subject" RelativeSource="{RelativeSource AncestorType=UserControl}" />
<Binding Path="Field" />
</MultiBinding>
</TextBox.Text>
</TextBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
SubjectDataFields
is a List<SubjectDataField>
. SubjectDataField
is defined as such:
public class SubjectDataField
{
[Key, Column(Order = 0)]
public string SubjectTypeIDFromServer { get; set; }
[Key, Column(Order = 1)]
public string Field { get; set; }
public string Name { get; set; }
public int DisplayOrder { get; set; }
public bool Required { get; set; }
public SubjectDataField()
{
}
}
I have created a converter to use multibinding in order to get the correct fields bound:
public class SubjectFieldValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length >= 2 && values[0] is Subject subject && values[1] is string fieldName)
{
string dynamicFieldPrefix = "dynamic_";
// Take dynamic fields into consideration
if (fieldName.StartsWith(dynamicFieldPrefix))
{
fieldName = fieldName.Substring(dynamicFieldPrefix.Length);
using (DbContext db = new DbContext())
{
return db.SubjectCustomDatas.Where(scd => scd.SubjectId == subject.Id && scd.Key == fieldName).FirstOrDefault()?.Value ?? "";
}
}
// Not a dynamic field, Retrieve the property, if it exists.
var propertyInfo = subject.GetType().GetProperty(fieldName);
if (propertyInfo != null)
return propertyInfo?.GetValue(subject);
return "";
}
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { Binding.DoNothing, Binding.DoNothing };
}
}
As you can see, some fields are actual properties from the object and are fetched using reflection, and some other have to go look into a dynamic fields table. The Convert function is working as intended. Both my properties and my dynamic fields are fetched properly, and performances look good.
However, when I wanted to implement the ConvertBack
method, I am having an issue. The value
contains the new value as entered in the text box, but I don't get neither the Subject
object, nor am I getting the Field name
. The Convert back receives a Type[] targetTypes
, but as I understand, this is nothing but the definition of types, so I do se Subject for the subject and String for the field name, but I don't see how I can actually access either the Subject itself or the Filed name itself.
I have asked GPT for help, but he quickly went into a circle. It tried to get me to add ConverterParameter
to the binding in the xaml and bind it with the subject, but then my page doesn't load at all, but I am not getting any error message... I am unsure how to debug this part. I am using the correct approach? What am I doing wrong?
Aucun commentaire:
Enregistrer un commentaire