Thanks for the help, Ali.
The FeatureSet object returned by the query task does contain field alias information (FeatureSet.FieldAliases). However, FeatureGrid only takes FeatureSet.Features, so it is clear why aliases are not being used.
I will try creating a copy of the features collection returned by the task, with aliases as column names, and pass it to the data grid.