【问题标题】:How To Bind Multiple Arrays to a DataGrid如何将多个数组绑定到 DataGrid
【发布时间】:2012-12-14 11:03:53
【问题描述】:

我有一个 Character 对象,其中有 10 个数组,代表角色的 10 个统计数据(敏捷、力量等 - 这是用于角色扮演游戏)。数组会跟踪统计数据并随着时间的推移而增加,所以我知道他们在哪个级别增加了哪个统计数据。数组是有限的,我一直跟踪到 50 级,所以我不需要跟踪可变数量的行或列的能力。一切都解决了。

例如字符串[] 敏捷 = 新字符串[50];

我想在 DataGrid 中显示此信息,并将每行中的每个单元格绑定到每个 stat 数组的元素。我找到并尝试了我认为是我最大的希望,一个名为 DataGrid2D 的库,但我无法尽我最大的努力让它工作。当我尝试更改 DataGrid 中的值时,我会收到错误消息:双向绑定需要 Path 或 XPath。当我从 ListBox 中选择字符时,填充了 10x50 的网格,即使这样也需要几秒钟来填充。

可在此处找到 DataGrid2D 示例:How to populate a WPF grid based on a 2-dimensional array。我使用了 Meleak 的答案(第二个),将 m_intArray 更改为从每个统计数据(c.Stats)创建的二维数组。

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

有没有更高效的解决方案?或者有谁知道为什么我会收到 DataGrid2D 的路径错误?

【问题讨论】:

  • 请问为什么要使用二维数组来显示数据列表?也许我误解了你,但似乎你想要一个常规数组来存储统计数据列表。
  • 它是 2D 的,因为 DataGrid2D 示例就是这样写在另一页上的。我不在乎它是如何完成的,只要它像描述的那样工作。

标签: c# wpf data-binding datagrid


【解决方案1】:

从您发布的链接中:“它是 DataGrid 的子类,并添加了一个名为 ItemsSource2D 的属性,用于绑定 2D 或 1D 源”

所以我猜你必须使用该库提供的 DataGrid 并使用 ItemsSource2D 属性

【讨论】:

  • 我正在使用库提供的 DataGrid,并且我也尝试使用 ItemsSource2D 属性,但它会引发错误:“System.Data.DataView”类型的对象无法转换为键入“System.Collections.Generic.IList`1[System.Data.DataRowView]”。在另一页的示例中,他也只使用了 ItemsSource。
【解决方案2】:

我有一个类似的问题,请看我的帖子: Two Way EntityCollection Binding to a Two Dimension Data Matrix

对于我也有一个固定数量并想要一个双向绑定的这一点,我定义了一个固定数量的 Columns 和 Rows,并将 Column 和 Row 属性动态分配给 ItemsControl 内的 TextBlock。

代码如下

<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>

它有点“脏代码”但是对于这个问题我没有找到任何其他解决方案:)

【讨论】:

    【解决方案3】:

    我花了很长时间才弄明白为什么你的程序不工作。

    基本上,如果我是正确的,您的 Character Class 将如下所示:

    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; }
    }
    

    Datagrid 不使用这些统计属性的原因是它们彼此分开。它不知道如何根据几个不同的属性创建行。

    正如 Nathan Cooper 之前指出的,您真正需要的是另一个名为 Stat(或类似的东西)的类,它可以将这些属性中的每一个都保存为 int。然后,您需要这些类的集合来将您的数据网格绑定到。

    这样想。您目前将数据垂直分组到列中。数据网格用于将数据分组为行。所以你需要一个代表一行的对象集合。

    我已经花时间创建了一个示例应用程序,它将展示这个概念的工作原理。

    字符类如下所示:

     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; }
        }
    }
    

    在这里你可以看到我创建了一个类似于 Nathan 所说的 Stat 类。就像我说的那样,这个类将容纳数据网格的“行”,因此可以以数据网格易于理解的方式对数据进行分组。

    表单的 XAML 如下所示:

    <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>
    

    我创建了一个组合框,用于选择要在 DataGrid 中显示的字符。此字符统计信息绑定到数据网格的列。

    最后是 ViewModel(不确定您是否使用 MVVM,但您应该使用。无论如何,这段代码可以放在后面的代码中,几乎不需要更改):

    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
                    }
                }
            });
    
        }
    
    
    }
    

    ViewModel 中的大部分空间都被我创建虚拟数据占用了,所以如果你愿意,可以随意删除它。重要的部分是 SelectedCharacter 和 Characters 类的创建。

    这是该项目的链接,您可以查看它的实际运行情况。 (请原谅我不擅长名字的糟糕名字) https://docs.google.com/open?id=0B9JOiSJxT9vjZVl1SHd3UzBiZEE

    祝你好运

    U_U

    【讨论】:

    • 感谢您抽出宝贵时间。我无法访问您的 google 文档,但我请求访问。在此期间,我将尝试使用您给我的东西。
    • 我想要做的是将统计数据显示为行,而不是列。因此,10 个统计数据中的每一个都将在数据网格中显示为一行。每列将代表角色的每个级别。当他们升级时,每个单元格都会显示他们增加了多少特定的统计数据。
    • @PapaSmurf 我很抱歉,我现在给了你访问权限。我了解行和列,也许我不擅长解释。看看这个例子,让我知道它是否有意义
    猜你喜欢
    • 1970-01-01
    • 2016-02-18
    • 2016-10-08
    • 2017-05-11
    • 2011-05-25
    • 2018-08-17
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多