Hi, I was recently, um, chastised for generating and loading XAML markup at runtime using XamlReader.Parse(). I was told that there's no reason to use XamlReader--it can always be done with static XAML, predetermined at design time.
I attempted to ask this person how I could construct a GridView to show pivoted data, where the number of columns and the binding path for each column is unknown at design time. I have yet to hear back, but even if I did, I figured this would be an interesting question to ask, because it might open my eyes (and others') to a better way of doing things.
My specific situation: Each "participant" is expected to perform a certain number of "blocks", but I don't know how many blocks there will be until I grab that data from the database. With that background in mind, my goal is to show a GridView that has the following columns:
Participant | Block 1 | Block 2 | ... | Block N |
(where N is the total number of blocks)
My current strategy is to dynamically loop through the blocks. For each block, I instantiate a new GridViewColumn, generate custom XAML to form a DataTemplate based on the BlockIndex, and use XamlReader.Parse() to set the column's CellTemplate.
Here is the code, just to make sure I'm being clear:
public void AddParticipantGridViewColumns()
{
GridView view = (GridView)_participantListView.View;
GridViewColumn column;
SetupViewModel setupViewModel = (SetupViewModel)DataContext;
foreach (int blockIndex in setupViewModel.BlockIndices)
{
column = BuildParticipantGridViewColumn(blockIndex);
view.Columns.Add(column);
}
}
public virtual GridViewColumn BuildParticipantGridViewColumn(int blockIndex)
{
string templateXaml = string.Format(@"
<DataTemplate
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
xmlns:local=""clr-namespace:Pse.ExperimentBase;assembly=ExperimentBase"">
<DataTemplate.Resources>
<local:BlockToBrushConverter
x:Key=""_blockToBrushConverter"" />
</DataTemplate.Resources>
<TextBlock
Style=""{{StaticResource _gridViewCenterItemStyle}}""
Text=""{{Binding Path=Block{0}.ConditionLabel}}""
Foreground=""{{Binding Path=Block{0}, Converter={{StaticResource _blockToBrushConverter}}}}"" />
</DataTemplate>",
blockIndex);
GridViewColumn column = new GridViewColumn();
column.Header = string.Format("Block {0}", blockIndex);
column.CellTemplate = (DataTemplate)XamlReader.Parse(templateXaml);
return column;
}
Is there some clever way I could do this with static XAML alone or is a dynamic solution, like the one I presented here, the only practical way to do it? Also, if there is a static solution, would you actually prefer it to the dynamic one?
Thanks,
-Dan