datatemplate dinâmica com ValueConverter
-
19-08-2019 - |
Pergunta
Eu quero mostrar dados em um datagrid WPFToolkit onde os dados é uma coleção de
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
}
onde o número de candidatos na lista de candidatos é configurável em tempo de execução.
desejados layout de grade olhares como este
Foo | Bar | Candidate 1 | Candidate 2 | ... | Candidate N
Assim, parece que não posso criar um DataTemplate para os candidatos em XAML como a expressão de ligação vai mudar.
Eu adicionar colunas necessárias em caso AutoGeneratedColumns assim:
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
});
}
}
Este, porém, falha com a seguinte exceção: faz o tag 'FooConverter' não existe no namespace XML 'clr-namespace: WpfToolkitDataGridTester; montagem = WpfToolkitDataGridTester'. Line '3' Posição '54'.
A alteração do StaticResource para DynamicResource não faz nenhuma mudança.
O que eu estou ausente?
FWIW: a codificado datatemplate
<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>
e a coluna modelo definido como assim
<wpftk:DataGridTemplateColumn CellTemplate="{StaticResource candidateTemplate}" />
'obras', mas, obviamente, não produz o resultado desejado como candidatos [0] é codificado.
Solução
Por alguma razão, ele funciona como esperado se eu fizer assim ...
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());
Outras dicas
Quando os arquivos XAML são compilados para BAML ele faz referência a montagem não o de origem na memória. Desde o BAML é compilado para o mesmo conjunto o tipo real ainda não está disponível.
Descobri que uma solução de curto prazo é comentar o estilo temporariamente, construir o projeto, em seguida, restaurar o estilo.
A solução mais permanente, porém, é para mover o conversor para outra montagem.
Isso ajudaria a declarar a FooConverter
uma vez a um nível superior (talvez como um recurso do DataGrid
) em vez de em cada DataTemplate
?