I have a XamDataGrid with table data giving a master detail relationship.
Master (Particle):
Fields: Name, Retention Time, Signals => detail
Detail (Signal):
Fields: Integral, Volume, Concentration…
Now the field integral can have different units thus the header must vary accordingly. As the signals are loaded dynamically and even the user can specify his own type of signals, the header label needs to be created on the fly for each record differently.
How can this be done?
Hello Horst,
I recommend reviewing the following blog on how to use the FieldLayoutInitialized event to add fields dynamically.
https://es.infragistics.com/community/blogs/b/blagunas/posts/xamdatagrid-dynamically-create-and-data-bind-columns-with-an-editor-of-your-choice
Let me know if you have any questions.
Hello Michael,
this blog has nothing in common with my question.
I was asking for varying headers of child records. The field names are static the headers(Field.Labels) have to be dynamic.
Regards Horst
You can try using a LabelPresenterStyle. I attached an example below. Let me know if you have any questions.
XamDataGridLabelBinding.zip
This example only works for the top level of the data structure but not for a detail dataset.
How can the "DataItem" of the detail set be accessed from the field properties?
Do you mean child fields in a hierarchy?
Yes, that is what I said even in my first post.
I also prefer to set the DataSource oft the DataPresenter than the DataContext.
regards Horst
In order to access child layout/fields you have to use line 80 and index into another sub layout and change the Label.
eg.this.xgrdCaseByWellSummary.FieldLayouts[1].Fields["LastNameWithEmailID"].Label
In my example I am also setting the DataSource property in Xaml. How and when do you want to bind your grid?
Hello Michal,
sorry I need to add to this thread again....
There is a problem with this solution.
If you open a FieldChooser related to this DataGrid the field using the dynamic label will show blank.
Even if you return a constant string from the Converter class.
Any solution to this problem?
sorry, I need to come back to this thread....
I now have the problem that with such a design if you open a FieeldChooser it will show a blank item for the dynamic Label even if you default to a constant string in the Converter Class.
great, this works exacly as expected!
Here is a blog post on changing out the sub field headers.
http://wpfthoughts.blogspot.com/2018/08/xamdatagrid-different-headings-on-child.html
to illustrate better what I mean here the grid with the current layout:
The "Area" field needs to have a varying header label according to the signal.
I am currently setting the grid during an update process caused by some internal state changes:
/// <summary> /// Redisplay if calibrations changed /// </summary> private void Update(object sender, EventArgs e) { Dispatcher.Invoke(() => { RunsTable.DataSource = null; RunsTable.DataSource = Project.CalculationRuns; AttachedResultsGraph.UpdateSeries(); }); }
To update the labels of the "Area" field i am currently using a rather crude work arround:
/// <summary> /// Show/hide signal names depending on run and /// Check if signal requires different area display and create new cloned layout accordingly /// </summary> private void RunsTable_AssigningFieldLayoutToItemDirect(object sender, AssigningFieldLayoutToItemEventArgs e) { Run run = e.Item as Run; if (run != null) { if (run.QuantitativeMultipleSignals) { e.FieldLayout = RunsTable.FieldLayouts["MultipleSignals"]; } else { e.FieldLayout = RunsTable.FieldLayouts["SingleSignal"]; } } Peak peak = e.Item as Peak; if (peak != null) { FieldLayout defaultLayout = RunsTable.FieldLayouts["Peak"]; string areaUnit = "V s"; Trace trace = peak.ParentTrace; if (string.IsNullOrEmpty(trace.AreaUnit) || trace.AreaUnit == areaUnit) { return; } if (trace != null) { areaUnit = trace.AreaUnit; FieldLayout existing = null; foreach (FieldLayout fieldLayout in RunsTable.FieldLayouts) { if (fieldLayout.Key.ToString() == areaUnit) { existing = fieldLayout; break; } } if (existing != null) { e.FieldLayout = existing; } else { FieldLayout layout = new FieldLayout(); layout.Key = areaUnit; foreach (Field field in defaultLayout.Fields) { Field clonedField = null; if (field is TextField) clonedField = new TextField(); if (field is NumericField) clonedField = new NumericField(); clonedField.Name = field.Name; clonedField.Format = field.Format; clonedField.Width = field.Width; clonedField.LabelTextAlignment = field.LabelTextAlignment; clonedField.HorizontalContentAlignment = field.HorizontalContentAlignment; clonedField.AllowEdit = field.AllowEdit; clonedField.AllowSorting = field.AllowSorting; clonedField.Visibility = field.Visibility; clonedField.ToolTip = field.ToolTip; clonedField.Settings.LabelPresenterStyle = field.Settings.LabelPresenterStyle; if (field.Name == "Area") { clonedField.Label = "Area\r[" + areaUnit + "]"; } else { clonedField.Label = field.Label; } layout.Fields.Add(clonedField); } RunsTable.FieldLayouts.Add(layout); e.FieldLayout = layout; } e.Handled = true; } } }
This approach looks for changes in the desired label and clones a new layout if no match found.
I think one can find a more elegant solution.