modèle de données dynamique avec valueconverter
-
19-08-2019 - |
Question
Je souhaite afficher des données dans une grille de données wpftoolkit contenant des données
.public class Thing
{
public string Foo { get; set; }
public string Bar { get; set; }
public List<Candidate> Candidates { get; set; }
}
public class Candidate
{
public string Name { get; set; }
public CandidateType CandidateType { get; set; }
}
public enum CandidateType
{
Type1,
Type2,
Type42
}
où le nombre de candidats dans la liste des candidats est configurable à l'exécution.
La disposition de grille souhaitée ressemble à ceci
Foo | Bar | Candidat 1 | Candidat 2 | ... | Candidat N
Il semble donc que je ne puisse pas créer de DataTemplate pour les candidats dans xaml car l'expression de liaison va changer.
J'ajoute les colonnes nécessaires à l'événement AutoGeneratedColumns comme suit:
private void DataGrid_AutoGeneratedColumns(object sender, EventArgs e)
{
ViewModel vm = DataContext as ViewModel;
for (int i = 0; i < vm.LotsOfThings.First().Candidates.Count; i++)
{
string assName = Assembly.GetExecutingAssembly().GetName().Name;
ParserContext ctx = new ParserContext();
ctx.XamlTypeMapper = new XamlTypeMapper(new string[] { assName });
ctx.XamlTypeMapper.AddMappingProcessingInstruction("src", "WpfToolkitDataGridTester", assName);
ctx.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
ctx.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
ctx.XmlnsDictionary.Add("src", "clr-namespace:WpfToolkitDataGridTester;assembly=" + assName);
var template = XamlReader.Parse(@"<DataTemplate>
<DataTemplate.Resources>
<src:FooConverter x:Key='fooConverter' />
</DataTemplate.Resources>
<TextBlock
Foreground='{Binding Candidates[" + i + @"].CandidateType,Converter={StaticResource fooConverter}}'
Text='{Binding Candidates[" + i + @"].Name}' />
</DataTemplate>", ctx) as DataTemplate;
dg.Columns.Add(new DataGridTemplateColumn
{
Header = "Candidate " + (i + 1),
CellTemplate = template
});
}
}
Cependant, cela échoue avec l'exception suivante: La balise 'FooConverter' n'existe pas dans l'espace de noms XML 'espace de noms clr: WpfToolkitDataGridTester; assembly = WpfToolkitDataGridTester'. Ligne '3' Position '54'.
La modification de StaticResource en DynamicResource ne change rien.
Qu'est-ce qui me manque?
FWIW: un modèle de données codé en dur
<DataTemplate x:Key="candidateTemplate">
<DataTemplate.Resources>
<src:FooConverter x:Key="fooConverter" />
</DataTemplate.Resources>
<TextBlock
Foreground="{Binding Candidates[0].CandidateType,Converter={StaticResource fooConverter}}"
Text="{Binding Candidates[0].Name}" />
</DataTemplate>
et la colonne de modèle définie comme telle
<wpftk:DataGridTemplateColumn CellTemplate="{StaticResource candidateTemplate}" />
'fonctionne' mais ne produit évidemment pas le résultat souhaité, car Candidates [0] est codé en dur.
La solution
Pour une raison quelconque, cela fonctionne comme prévu si je fais comme ça ...
string assName = Assembly.GetExecutingAssembly().GetName().Name;
StringBuilder sb = new StringBuilder();
sb.Append("<DataTemplate ");
sb.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' ");
sb.Append("xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' ");
sb.Append("xmlns:src='clr-namespace:WpfToolkitDataGridTester;assembly=" + assName + "' >");
sb.Append("<DataTemplate.Resources>");
sb.Append("<src:FooConverter x:Key='fooConverter' />");
sb.Append("</DataTemplate.Resources>");
sb.Append("<TextBlock ");
sb.Append("Foreground='{Binding Candidates[" + i + "].CandidateType,Converter={StaticResource fooConverter}}' ");
sb.Append("Text='{Binding Candidates[" + i + @"].Name}' />");
sb.Append("</DataTemplate>");
var template = (DataTemplate)XamlReader.Parse(sb.ToString());
Autres conseils
Lorsque les fichiers XAML sont compilés au format BAML, il fait référence à l'assembly , pas à la source en mémoire. Le BAML étant compilé dans le même assemblage, le type actuel n’est pas encore disponible.
J'ai constaté qu'une solution de contournement à court terme consiste à commenter temporairement le style, à construire le projet, puis à restaurer le style.
La solution la plus permanente consiste toutefois à déplacer le convertisseur vers un autre assemblage.
Est-ce utile de déclarer le FooConverter
une fois à un niveau supérieur (peut-être en tant que ressource du DataGrid
) au lieu de chaque DataTemplate
?