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 Allignment { 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
CodePudding user response:
You can bind the DataGrid's ItemsSource to a list with some common interface. So instead of binding to List<Player> and List<Monster>:
List<ITableEntry>
Or you can try to use an abstract class instead.
CodePudding user response:
you can use PriorityBinding:
<DataGridTextColumn Header="AC">
<DataGridTextColumn.Binding>
<PriorityBinding>
<Binding Path="Ac" />
<Binding Path="Stats.Ac" />
</PriorityBinding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
CodePudding user response:
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.