I currently have 2 lists with different classes in them: List<Player>
and List<Monster>
.
I want to get these two lists in a single Datagrid as follows:
The reason I need them to be in one Datagrid, is that I need to sort on Initiative, and show the order from high to low. The Datagrid also need to work with any number of players/monsters. The classes look as follows:
public partial class Player
{
public bool IsInParty { get; set; }
public string Name { get; set; }
public int Ac { get; set; }
public string ArmorType { get; set; }
public string[] Speed { get; set; }
public int InitiativeBonus { get; set; }
public string[] DmgVul { get; set; }
public string[] DmgRes { get; set; }
public string[] DmgImm { get; set; }
public string[] CondImm { get; set; }
public string[] Senses { get; set; }
public string[] Languages { get; set; }
public NameValuePair[] Conditions { get; set; }
public int Id { get; set; }
}
public partial class Monster
{
public BaseMonster Stats { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public int Hp { get; set; }
public List<int> Damage { get; set; }
public bool IsOverhealed => Hp > Stats.MaxHp;
public bool IsBloody => Hp <= Stats.MaxHp / 2.0;
public bool IsNearDeath => Hp <= Stats.MaxHp / 4.0;
public bool IsDead => Hp <= 0;
public List<NameValuePair> Conditions { get; set; }
}
public partial class BaseMonster
{
public int DefaultId { get; set; }
public string DefaultName { get; set; }
public string Type { get; set; }
public string Alignment { get; set; }
public int Ac { get; set; }
public string ArmorType { get; set; }
public int MaxHp { get; set; }
public string HitDice { get; set; }
public string[] Speed { get; set; }
public int Str { get; set; }
public int Dex { get; set; }
public int Con { get; set; }
public int Int { get; set; }
public int Wis { get; set; }
public int Cha { get; set; }
public string[] SavThrProf { get; set; }
public string[] SkillProf { get; set; }
public string[] DmgVul { get; set; }
public string[] DmgRes { get; set; }
public string[] DmgImm { get; set; }
public string[] CondImm { get; set; }
public string[] Senses { get; set; }
public string[] Languages { get; set; }
public string Challenge { get; set; }
public NameValuePair[] Traits { get; set; }
public NameValuePair[] Actions { get; set; }
public NameValuePair[] LegendaryActions { get; set; }
public string LairActions { get; set; }
public string RegionalEffects { get; set; }
}
Because I am relatively new to front-end and xaml, I have a little trouble how to take on this problem. Currently I've managed to get the following with some test data:
<Grid Grid.Row="2" Grid.Column="1">
<DataGrid x:Name="creatureDatagrid">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTextColumn Header="ID" Binding="{Binding Id}"/>
<DataGridTextColumn Header="AC" Binding="{Binding Ac}"/>
<DataGridTextColumn Header="HP" Binding="{Binding Hp}"/>
</DataGrid.Columns>
</DataGrid>
<Grid/>
As you can see, some values work fine, but in this case AC is not working, because AC in found in BaseMonster
in the Monster
class
DataGrid columns are generated automatically based on the type of ItemsSource items. See this blogpost to get some more insights about this.
Since a DataGrid can only be bound to a single type / collection you first need to create a common interface which contains all common properties like
public interface ICreature
{
int Id { get; set; }
//Other common properties
}
If the items are not changed at runtime (otherwise use ObservableCollections), you can simply bind the DataGrid to the concatenated collections
public IEnumerable<ICreature> Creatures { get; } = Players.Concat(Monsters);
This will autogenerate all interface defined properties in your DataGrid. All additional properties, you need to define in XAML since they can't be autogenerated:
<DataGrid ItemsSource="{Binding Creatures}">
<DataGrid.Columns>
<DataGridTextColumn Header="CustomProperty" Binding="{Binding Name}"/>
<!-- More custom properties -->
</DataGrid.Columns>
</DataGrid>
Use PriorityBinding for columns accessing different properties:
<DataGridTextColumn Header="MixedProperty"
<DataGridTextColumn.Binding>
<PriorityBinding>
<Binding Path="PlayersProperty"/>
<Binding Path="MonstersProperty"/>
</PriorityBinding>
<DataGridTextColumn.Binding>
</DataGridTextColumn>
Note that autogeneration of columns also can be disabled to define all columns by your own.