Consegui tornar possível adicionar dinamicamente uma coluna usando apenas uma linha de código como esta:
MyItemsCollection.AddPropertyDescriptor(
new DynamicPropertyDescriptor<User, int>("Age", x => x.Age));
Em relação à pergunta, essa não é uma solução baseada em XAML (já que, como mencionado, não há uma maneira razoável de fazê-lo), nem é uma solução que funcionaria diretamente com o DataGrid.Columns. Na verdade, ele opera com o ItemsSource ligado ao DataGrid, que implementa ITypedList e, como tal, fornece métodos personalizados para a recuperação do PropertyDescriptor. Em um lugar no código, você pode definir "linhas de dados" e "colunas de dados" para sua grade.
Se você tivesse:
IList<string> ColumnNames { get; set; }
//dict.key is column name, dict.value is value
Dictionary<string, string> Rows { get; set; }
você poderia usar por exemplo:
var descriptors= new List<PropertyDescriptor>();
//retrieve column name from preprepared list or retrieve from one of the items in dictionary
foreach(var columnName in ColumnNames)
descriptors.Add(new DynamicPropertyDescriptor<Dictionary, string>(ColumnName, x => x[columnName]))
MyItemsCollection = new DynamicDataGridSource(Rows, descriptors)
e sua grade usando a ligação a MyItemsCollection seria preenchida com as colunas correspondentes. Essas colunas podem ser modificadas (novas adicionadas ou removidas) em tempo de execução dinamicamente e a grade atualizará automaticamente sua coleção de colunas.
O DynamicPropertyDescriptor mencionado acima é apenas uma atualização para o PropertyDescriptor regular e fornece uma definição de colunas fortemente tipada com algumas opções adicionais. Caso contrário, o DynamicDataGridSource funcionaria bem com o PropertyDescriptor básico.