Home > Software engineering >  Making a custom Datagrid, how should I tackle this problem?
Making a custom Datagrid, how should I tackle this problem?

Time:11-30

Currently I am trying to create a table containing information of Players and Monsters. I do however notice that the way I am currently trying it in, seem to have some limits which do not satisfy my needs. I would like the table to look as the following:

enter image description here

I've created a Player class and a Monster class which contain the information of the entities. Features I would like for my table are the following:

  • Any number of Player/Monsters
  • Sort on INIT, which is randomly generated (1-20)
  • Edit things on the fly (ObservableCollection<>?)
  • Hover over underscored text to display information on the move (I've created a NameValuePair class with a name and value

I've tried to do things as the following, but it has this result.

<Grid Grid.Row="2" Grid.Column="1">
    <DataGrid x:Name="creatureDatagrid">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
            <DataGridTextColumn Header="maxHP" Binding="{Binding MaxHp}"/>
            <DataGridTextColumn Header="AC" Binding="{Binding Ac}"/>
            <DataGridTextColumn Header="INIT" Binding="{Binding Dex}"/>
            <DataGridTextColumn Header="HP" Binding="{Binding Hp}"/>
            <DataGridTextColumn Header="Senses" Binding="{Binding DmgRes}"/>
            <DataGridTextColumn Header="Speed" Binding="{Binding Speed}"/>
            <DataGridTextColumn Header="Senses" Binding="{Binding Senses}"/>
            <DataGridTextColumn Header="Traits" Binding="{Binding Traits}"/>
            <DataGridTextColumn Header="Actions" Binding="{Binding Actions}"/>
            <DataGridTextColumn Header="Conditions" Binding="{Binding Conditions}"/>
        </DataGrid.Columns>
        </DataGrid>
</Grid>

enter image description here

As you can see, I struggle to convert the arrays into text, let alone convert the NameValuePair to name hoverable value

What would be a way to create a table like the one in the example? Is this even possible for WPF, or am I better of which a different front-end framework? Thanks!

Some more information on my code/classes below:

public partial class MainWindow : Window
        {
            private readonly MonsterService _monsterService;
            private readonly DatabaseService _databaseService;
            public MainWindow()
            {
                InitializeComponent();
                _monsterService = new MonsterService();
                _databaseService= new DatabaseService();
                foreach (var player in _databaseService.Players)
                {
                    creatureDatagrid.Items.Add(player);
                }
                _databaseService.DoStuff();
                foreach (var monster in _databaseService.ActiveMonsters)
                {
                    creatureDatagrid.Items.Add(monster);
                }
            }
        }
    
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 BaseMonster
    {
        public int BaseId { get; set; }
        public string BaseName { 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; }
    }
    
public partial class Monster : BaseMonster
    {
        public Monster(BaseMonster baseObject) 
        {
            this.BaseId = baseObject.BaseId;
            this.BaseName = baseObject.BaseName;
            this.Type = baseObject.Type;
            this.Allignment = baseObject.Allignment;
            this.Ac = baseObject.Ac;
            this.ArmorType = baseObject.ArmorType;
            this.MaxHp = baseObject.MaxHp;
            this.HitDice = baseObject.HitDice;
            this.Speed = baseObject.Speed;
            this.Str = baseObject.Str;
            this.Dex = baseObject.Dex;
            this.Con = baseObject.Con;
            this.Int = baseObject.Int;
            this.Wis = baseObject.Wis;
            this.Cha = baseObject.Cha;
            this.SavThrProf = baseObject.SavThrProf;
            this.SkillProf = baseObject.SkillProf;
            this.DmgVul = baseObject.DmgVul;
            this.DmgRes = baseObject.DmgRes;
            this.DmgImm = baseObject.DmgImm;
            this.CondImm = baseObject.CondImm;
            this.Senses = baseObject.Senses;
            this.Languages = baseObject.Languages;
            this.Challenge = baseObject.Challenge;
            this.Traits = baseObject.Traits;
            this.Actions = baseObject.Actions;
            this.LegendaryActions = baseObject.LegendaryActions;
            this.LairActions = baseObject.LairActions;
            this.RegionalEffects = baseObject.RegionalEffects;
        }
        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 > MaxHp;
        public bool IsBloody => Hp <= MaxHp / 2.0;
        public bool IsNearDeath => Hp <= MaxHp / 4.0;
        public bool IsDead => Hp <= 0;
        public List<NameValuePair> Conditions { get; set; }
    }

CodePudding user response:

Instead of binding directly to a string[] property, you could add another string property to your Player class that returns the actual value that you want to display in the DataGrid, e.g.:

public string SensesDisplayValue => string.Join(",", Senses);

This effectively makes the Player class a kind of view model. If it's currently something else, you should replace it with a view model and add the view-friendly property to this one. Binding directly to some kind of entity or business object is usually not a good idea.

The other option is to use a converter in the view to convert the array to a string value.

  • Related