0

I've got a Character object, in which I've got 10 arrays, representing 10 statistics of the character (agility, strength, etc - this is for a role playing game). The arrays keep track of the stat and increases to it over time, so I know at which level they increased which stat. The arrays are finite, I keep track up to level 50, so I don't need the ability to track a variable number of rows or columns. Everything is fixed.

e.g. string[] Agility = new string[50];

I want to display this information in a DataGrid, and bind each cell in each row to an element of each stat array. I found and tried what I thought was my best hope, a library called DataGrid2D, but could not get it to work with my best effort. When I tried to change the value in the DataGrid I would get the error: Two-way binding requires Path or XPath. The 10x50 grid was populated when I selected the character from a ListBox, and even that took a couple seconds to populate.

The DataGrid2D example was found here: How to populate a WPF grid based on a 2-dimensional array. I used Meleak's answer (the 2nd one down), changing out m_intArray for a 2D array created from each of the stats (c.Stats).

var c = CE_Characters_charactersLB.SelectedItem as Character;
var dg = CE_Characters_statsDG;
dg.ItemsSource = GetBindable2DArray<string>(c.Stats);

Is there a solution that is more efficient? Or does anyone know why I get the Path error with DataGrid2D?

Community
  • 1
  • 1
Aaron D.
  • 141
  • 1
  • 4
  • 15
  • May I ask why you want to use a 2-D array to display a list of data? Maybe I've misunderstood you but it seems as though you would want a regular array to store a list of stats. – Jason Ridge Dec 14 '12 at 12:17
  • It's 2D because that's how the DataGrid2D example is written on the other page. I don't care how it's done as long as it works as described. – Aaron D. Dec 14 '12 at 12:23

3 Answers3

0

From the link you posted: "It subclasses DataGrid and adds a property called ItemsSource2D which is used for binding against 2D or 1D sources"

So i guess you have to use the DataGrid provided with that library and use ItemsSource2D property

Dtex
  • 2,593
  • 1
  • 16
  • 17
  • I am using the DataGrid provided with the library, and I have tried to use the ItemsSource2D property as well, but it throws an error: Object of type 'System.Data.DataView' cannot be converted to type 'System.Collections.Generic.IList`1[System.Data.DataRowView]'. In the example on the other page he just uses ItemsSource as well. – Aaron D. Dec 14 '12 at 12:08
0

I had a similar question, please look at my thread: Two Way EntityCollection Binding to a Two Dimension Data Matrix

For the point that I also had a fixed amout and wanted a TwoWay Binding I defined a fixed amout of Columns and Rows and assigned the Column and Row Property dynamically to a TextBlock inside an ItemsControl.

Heres the Code

<ItemsControl ItemsSource="{Binding Path=CustomerTankDayStructure,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                                              Grid.Column="1"
                                              Grid.Row="2">
                                    <ItemsControl.ItemsPanel>
                                        <ItemsPanelTemplate>
                                            <Grid helper:EnterKeyTraversal.IsEnabled="True"
                                                  KeyboardNavigation.TabNavigation="Local">
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="0" />
                                                    [...]
                                                    <ColumnDefinition Width="30" />
                                                </Grid.ColumnDefinitions>
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="0" />
                                                    <RowDefinition Height="30" />
                                                    [...]
                                                    <RowDefinition Height="30" />
                                                </Grid.RowDefinitions>
                                            </Grid>
                                        </ItemsPanelTemplate>
                                    </ItemsControl.ItemsPanel>
                                    <ItemsControl.ItemContainerStyle>
                                        <Style>
                                            <Setter Property="Grid.Column" Value="{Binding Path=DoW}" />
                                            <Setter Property="Grid.Row" Value="{Binding Path=HoD}" />
                                        </Style>
                                    </ItemsControl.ItemContainerStyle>
                                    <ItemsControl.ItemTemplate>
                                        <DataTemplate>
                                            <Border BorderThickness="0,0,1,1"
                                                    Style="{StaticResource ResourceKey=DefaultBorder}">
                                                <TextBox BorderThickness="0"
                                                         MaxLength="3"
                                                         Style="{StaticResource ResourceKey=EditableTextBoxWithoutWarningForTanks}"
                                                         TextAlignment="Center"
                                                         VerticalContentAlignment="Center"
                                                         IsTabStop="True">
                                                    <TextBox.TabIndex>
                                                        <MultiBinding Converter="{StaticResource ResourceKey=CustomerTankTabIndexConverter}">
                                                            <Binding Path="DoW" />
                                                            <Binding Path="HoD" />
                                                        </MultiBinding>
                                                    </TextBox.TabIndex>
                                                    <TextBox.Text>
                                                        <Binding Path="Value"
                                                                 Mode="TwoWay"
                                                                 NotifyOnValidationError="True"
                                                                 TargetNullValue=""
                                                                 UpdateSourceTrigger="PropertyChanged">
                                                            <Binding.ValidationRules>
                                                                <validator:Int32Validator Mandatory="True" 
                                                                                          Min="0" 
                                                                                          Max="100" />
                                                            </Binding.ValidationRules>
                                                        </Binding>

                                                    </TextBox.Text>
                                                </TextBox>
                                            </Border>
                                        </DataTemplate>
                                    </ItemsControl.ItemTemplate>
                                </ItemsControl>

Its kinda "dirty code" but for this problem I didnt find any other solution :)

Community
  • 1
  • 1
Johannes Wanzek
  • 2,825
  • 2
  • 29
  • 47
0

It took me an embarrassingly long amount of time to figure out why your program isn't working.

Basically if I am correct, your Character Class will look something like this:

public class Character
{
      public string Name { get; set; }
      public int Level { get; set; }          
      public int[] Agility { get; set; }         
      public int[] Strength { get; set; }         
      public int[] Stamina { get; set; }         
      public int[] Intelligence { get; set; }
}

The reason why the Datagrid isn't working with these stat properties as they are separate from each other. It doesn't know how to create rows based on several distinct properties.

What you really need, as Nathan Cooper pointed out before, is another class called Stat (or something similar) that can house each of these properties as ints. You then need a collection of these classes to bind your datagrid to.

Think about it like this. You currently have your data grouped vertically into columns. Datagrids are used to data being grouped into rows. So you need a collection of objects that represent a row.

I have taken the time to create an example application which will show the concept working.

The Character Class looks like this:

 public class Character
 {
    public string Name { get; set; }

    public int Level { get; set; }

    public List<Stat> Stats { get; set; }

    public Character()
    {

    }

    public class Stat
    {
        public int Agility { get; set; }
        public int Strength { get; set; }
        public int Intelligence { get; set; }
        public int Stamina { get; set; }
    }
}

Here you can see I created a Stat class similar to what Nathan was talking about. Like I said this class will house the "rows" of the datagrid so the data can be grouped in a way that the datagrid can easily understand.

The XAML of the form looks like this:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>

    <ComboBox Margin="5,5,5,5" DisplayMemberPath="Name" Grid.Row="0"  ItemsSource="{Binding Path=Characters}"  SelectedItem="{Binding Path=SelectedCharacter}"></ComboBox>
    <DataGrid Grid.Row="1" Margin="5,5,5,5" AutoGenerateColumns="True" ItemsSource="{Binding Path=SelectedCharacter.Stats}" >
        <DataGrid.Columns>
            <DataGridTextColumn Header="Agility" Binding="{Binding Path=Agility}"></DataGridTextColumn>
            <DataGridTextColumn Header="Strength" Binding="{Binding Path=Strength}"></DataGridTextColumn>
            <DataGridTextColumn Header="Intelligence" Binding="{Binding Path=Intelligence}"></DataGridTextColumn>
            <DataGridTextColumn Header="Stamina" Binding="{Binding Path=Stamina}"></DataGridTextColumn>
        </DataGrid.Columns>

    </DataGrid>
</Grid>

I created a combobox that will select the character to display in the DataGrid. This characters stats are bound to the columns of the datagrid.

Lastly here is the ViewModel (not sure if you are using MVVM but you prolly should. anyway this code could go in the code behind with little changing required):

public class MainWindowViewModel:ViewModelBase
{
    private IList<Character> _characters;
    public IList<Character> Characters
    {
        get
        {
            return _characters;
        }
        set
        {
            _characters = value;
            RaisePropertyChanged(()=>Characters);
        }
    }

    private Character _character;
    public Character SelectedCharacter
    {
        get
        {
            return _character;
        }
        set
        {
            _character = value;
            RaisePropertyChanged(()=>SelectedCharacter);
        }
    }

    public MainWindowViewModel()
    {
        InitializeCharacters();
    }

    private void InitializeCharacters()
    {
        Characters = new List<Character>();
        SelectedCharacter = new Character();
        Characters.Add(new Character
        {
            Name = "Tank",
            Level = 3,
            Stats = new List<Character.Stat>()
            {
                new Character.Stat()
                {
                    Agility =       10,
                    Intelligence =  8, 
                    Strength =      14,
                    Stamina =       16
                },

                    new Character.Stat()
                {
                    Agility =      11,
                    Intelligence = 9, 
                    Strength =     16,
                    Stamina =      18
                },

                    new Character.Stat()
                {
                    Agility =       12,
                    Intelligence = 10, 
                    Strength =      17,
                    Stamina =       20
                }
            }



        });

        Characters.Add(new Character 
        { 
            Name = "Healer", 
            Level = 4, 

              Stats = new List<Character.Stat>()
            {
                new Character.Stat()
                {
                    Agility =       10,
                    Intelligence =  14,
                    Strength =       8,
                    Stamina =       10
                },

                    new Character.Stat()
                {
                    Agility =      11,
                    Intelligence = 16,
                    Strength =     9, 
                    Stamina =      11
                },

                    new Character.Stat()
                {
                    Agility =      12,
                    Intelligence = 17,
                    Strength =    10, 
                    Stamina =      13
                },
                    new Character.Stat()
                {
                    Agility =       14,
                    Intelligence =  20,
                    Strength =     10, 
                    Stamina =       14
                }
            }
        });

        Characters.Add(new Character 
        { 
            Name = "Ranger", 
            Level = 6,  

            Stats = new List<Character.Stat>()
            {
                new Character.Stat()
                {
                    Agility =        12,
                    Intelligence =   8, 
                    Strength =       10,
                    Stamina =        8
                },

                    new Character.Stat()
                {
                    Agility =      14,
                    Intelligence = 9,
                    Strength =     11,
                    Stamina =     10
                },

                    new Character.Stat()
                {
                    Agility =       17,
                    Intelligence = 10, 
                    Strength =     12,
                    Stamina =      11
                },
                    new Character.Stat()
                {
                    Agility =      18,
                    Intelligence =11,
                    Strength =    13,
                    Stamina =     12
                },

                    new Character.Stat()
                {
                    Agility =       20,
                    Intelligence = 12,
                    Strength =     15,
                    Stamina =      13
                },
                    new Character.Stat()
                {
                    Agility =      22,
                    Intelligence = 13,
                    Strength =     16,
                    Stamina =      13
                }
            }
        });

    }


}

Most of the space in the ViewModel is taken up by me creating dummy data, so feel free to delete it if you like. The important part is the creation of the SelectedCharacter and Characters Classes.

Here is a link to the project so you can see it in action. (excuse the shitty name I am bad at names) https://docs.google.com/open?id=0B9JOiSJxT9vjZVl1SHd3UzBiZEE

Good Luck

U_U

Jason Ridge
  • 1,868
  • 15
  • 27
  • Thanks for taking the time on this. I lacked access to your google docs, but I requested access. In the meantime I'll try to work with what you've given me. – Aaron D. Dec 14 '12 at 15:04
  • What I'm trying to do is display the stats as rows, not columns. So each of the 10 stats will show as a row in the datagrid. And each column will represent each level of the character. Each cell will show how much they have increased a particular stat when they level up. – Aaron D. Dec 14 '12 at 15:08
  • @PapaSmurf im so sorry, I gave you access now. I understand about the rows and Columns, perhaps I'm just bad at explaining. Take a look at the example and let me know if it makes sense – Jason Ridge Dec 15 '12 at 15:47