If you're doing it with a GridView, I don't know of a solution to that little issue...
But if you delve into the ItemTemplate and handle the columns yourself, you might be able to hack something like that in...
<ListView.ItemTemplate>
<DataTemplate DataType="...">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="..."/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding col0Text}"
Grid.ColumnSpan="{Binding col1Text,Converter={StaticResource cnvOneOrTwo}"
/>
<TextBlock Grid.Column="1" Text="{Binding col1Text}"/>
<TextBlock Grid.Column="2" Text="{Binding col2Text}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
(Note: Code entered here, so not tested/debugged)
Basically, create a custom IValueConverter that would take the contents of the NEXT column as an argument, and return 1 if it's populated or 2 if it's empty. You could even pass the entire bound record, and have your converter check each column for data and determine the correct ColumnSpan.
It's not a one-line solution, but it might do the trick.