none
如何将二维数组绑定并显示在DataGrid中? RRS feed

  • 问题

  • 打算将一个二维整型数组显示在DataGrid中,每个DataGridCell为一个数组元素,请问如何将每个数组元素双向绑定到DataGrid中?谢谢!

    2011年6月1日 7:57

答案

  • 二维数组本身没有实现INotifyPropertyChanged接口,所以要实现双向绑定并且从数组更新来改变前面DataGrid的值是不可以的。不过如果选择一个二维结构的集合就可以办到,看我的例子:

     

    注意: 绑定二维结构到DataGrid中,其中第二维的元素数量必须都一样,比如下面的例子中,第二维必须都是9个元素,否则在DataGrid中每一行就可能有不同数量的列。这个是无法实现每一行列的数量不同的。

     

    <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="*"/>
          <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <DataGrid x:Name="dg1" ItemsSource="{Binding ArraySource}" AutoGenerateColumns="False" CanUserAddRows="False">
          <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding [0]}" Header="index:0"/>
            <DataGridTextColumn Binding="{Binding [1]}" Header="index:1"/>
            <DataGridTextColumn Binding="{Binding [2]}" Header="index:2"/>
            <DataGridTextColumn Binding="{Binding [3]}" Header="index:3"/>
            <DataGridTextColumn Binding="{Binding [4]}" Header="index:4"/>
            <DataGridTextColumn Binding="{Binding [5]}" Header="index:5"/>
            <DataGridTextColumn Binding="{Binding [6]}" Header="index:6"/>
            <DataGridTextColumn Binding="{Binding [7]}" Header="index:7"/>
            <DataGridTextColumn Binding="{Binding [8]}" Header="index:8"/>
          </DataGrid.Columns>
        </DataGrid>
        <DataGrid x:Name="dg2" Grid.Row="1" ItemsSource="{Binding CollectionSource}" AutoGenerateColumns="False" CanUserAddRows="False">
          <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding [0].value}" Header="index:0"/>
            <DataGridTextColumn Binding="{Binding [1].value}" Header="index:1"/>
            <DataGridTextColumn Binding="{Binding [2].value}" Header="index:2"/>
            <DataGridTextColumn Binding="{Binding [3].value}" Header="index:3"/>
            <DataGridTextColumn Binding="{Binding [4].value}" Header="index:4"/>
            <DataGridTextColumn Binding="{Binding [5].value}" Header="index:5"/>
            <DataGridTextColumn Binding="{Binding [6].value}" Header="index:6"/>
            <DataGridTextColumn Binding="{Binding [7].value}" Header="index:7"/>
            <DataGridTextColumn Binding="{Binding [8].value}" Header="index:8"/>
          </DataGrid.Columns>
        </DataGrid>     
      </Grid>
    </Window>
    

     

    C#:

      public partial class MainWindow : Window
      {
     
        public int[][] ArraySource { getset; }
     
        public ObservableCollection<items> CollectionSource { getset; }
     
        public MainWindow()
        {
          InitializeComponent();
     
          // For ArraySource
          ArraySource = new int[][] {      
            new int[]{1,2,3,4,5,6,7,8,9},
            new int[]{11,12,13,14,15,16,17,18,19},
            new int[]{21,22,23,24,25,26,27,28,29},
            new int[]{31,32,33,34,35,36,37,38,39},
            new int[]{41,42,43,44,45,46,47,48,49}
          };
     
          // For CollectionSource
          CollectionSource = new ObservableCollection<items>()
          {
            new items(){new item(1),new item(2),new item(3),new item(4),new item(5),new item(6),new item(7),new item(8),new item(9)},
            new items(){new item(11),new item(12),new item(13),new item(14),new item(15),new item(16),new item(17),new item(18),new item(19)},
            new items(){new item(21),new item(22),new item(23),new item(24),new item(25),new item(26),new item(27),new item(28),new item(29)},
            new items(){new item(31),new item(32),new item(33),new item(34),new item(35),new item(36),new item(37),new item(38),new item(39)},
            new items(){new item(41),new item(42),new item(43),new item(44),new item(45),new item(46),new item(47),new item(48),new item(49)},
     
          };
     
          // Set the DataContext of Window
          this.DataContext = this;
        }
      }
     
      public class items : ObservableCollection<item> { }
     
      public class item : INotifyPropertyChanged
      {
        public item(int v) { value = v; }
        private int _value;
        public int value
        {
          get { return _value; }
          set
          {
            _value = value;
            if (PropertyChanged != null)
              PropertyChanged(thisnew PropertyChangedEventArgs("value"));
          }
        }
        public event PropertyChangedEventHandler PropertyChanged;
      }

     

    下载:http://cid-51b2fdd068799d15.office.live.com/self.aspx/.Public/Samples%5E_2011/20110602%5E_Binding2DArrayInDataGrid.zip

     


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年6月1日 18:26
    版主
  • 有个错误,你是动态增加CellTemplate,但是你没有动态指定每个列要绑定item的索引。

    你应该动态生成DataTemplate 并且绑定是要带索引的:

    修改你的 AutoGeneratingColumn 事件Handler

     

        void dgData_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
          for (int columnIndex = 0; columnIndex < this.CollectionSource[0].Count; columnIndex++)
          {
            DataGridTemplateColumn column = new DataGridTemplateColumn();
            XmlTextReader sr = new XmlTextReader(
              new StringReader(
                "<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">" +
                  "<TextBox Visibility=\"{Binding [" + columnIndex + "].Visible}\" Text=\"{Binding [" + columnIndex + "].Value}\"/>" +
                "</DataTemplate>"));
     
            column.CellTemplate = (DataTemplate)XamlReader.Load(sr);
            (sender as DataGrid).Columns.Add(column);
          }
          e.Column = null;
        }
    Sincerely,

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年6月20日 10:52
    版主

全部回复

  • 二维数组本身没有实现INotifyPropertyChanged接口,所以要实现双向绑定并且从数组更新来改变前面DataGrid的值是不可以的。不过如果选择一个二维结构的集合就可以办到,看我的例子:

     

    注意: 绑定二维结构到DataGrid中,其中第二维的元素数量必须都一样,比如下面的例子中,第二维必须都是9个元素,否则在DataGrid中每一行就可能有不同数量的列。这个是无法实现每一行列的数量不同的。

     

    <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="*"/>
          <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <DataGrid x:Name="dg1" ItemsSource="{Binding ArraySource}" AutoGenerateColumns="False" CanUserAddRows="False">
          <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding [0]}" Header="index:0"/>
            <DataGridTextColumn Binding="{Binding [1]}" Header="index:1"/>
            <DataGridTextColumn Binding="{Binding [2]}" Header="index:2"/>
            <DataGridTextColumn Binding="{Binding [3]}" Header="index:3"/>
            <DataGridTextColumn Binding="{Binding [4]}" Header="index:4"/>
            <DataGridTextColumn Binding="{Binding [5]}" Header="index:5"/>
            <DataGridTextColumn Binding="{Binding [6]}" Header="index:6"/>
            <DataGridTextColumn Binding="{Binding [7]}" Header="index:7"/>
            <DataGridTextColumn Binding="{Binding [8]}" Header="index:8"/>
          </DataGrid.Columns>
        </DataGrid>
        <DataGrid x:Name="dg2" Grid.Row="1" ItemsSource="{Binding CollectionSource}" AutoGenerateColumns="False" CanUserAddRows="False">
          <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding [0].value}" Header="index:0"/>
            <DataGridTextColumn Binding="{Binding [1].value}" Header="index:1"/>
            <DataGridTextColumn Binding="{Binding [2].value}" Header="index:2"/>
            <DataGridTextColumn Binding="{Binding [3].value}" Header="index:3"/>
            <DataGridTextColumn Binding="{Binding [4].value}" Header="index:4"/>
            <DataGridTextColumn Binding="{Binding [5].value}" Header="index:5"/>
            <DataGridTextColumn Binding="{Binding [6].value}" Header="index:6"/>
            <DataGridTextColumn Binding="{Binding [7].value}" Header="index:7"/>
            <DataGridTextColumn Binding="{Binding [8].value}" Header="index:8"/>
          </DataGrid.Columns>
        </DataGrid>     
      </Grid>
    </Window>
    

     

    C#:

      public partial class MainWindow : Window
      {
     
        public int[][] ArraySource { getset; }
     
        public ObservableCollection<items> CollectionSource { getset; }
     
        public MainWindow()
        {
          InitializeComponent();
     
          // For ArraySource
          ArraySource = new int[][] {      
            new int[]{1,2,3,4,5,6,7,8,9},
            new int[]{11,12,13,14,15,16,17,18,19},
            new int[]{21,22,23,24,25,26,27,28,29},
            new int[]{31,32,33,34,35,36,37,38,39},
            new int[]{41,42,43,44,45,46,47,48,49}
          };
     
          // For CollectionSource
          CollectionSource = new ObservableCollection<items>()
          {
            new items(){new item(1),new item(2),new item(3),new item(4),new item(5),new item(6),new item(7),new item(8),new item(9)},
            new items(){new item(11),new item(12),new item(13),new item(14),new item(15),new item(16),new item(17),new item(18),new item(19)},
            new items(){new item(21),new item(22),new item(23),new item(24),new item(25),new item(26),new item(27),new item(28),new item(29)},
            new items(){new item(31),new item(32),new item(33),new item(34),new item(35),new item(36),new item(37),new item(38),new item(39)},
            new items(){new item(41),new item(42),new item(43),new item(44),new item(45),new item(46),new item(47),new item(48),new item(49)},
     
          };
     
          // Set the DataContext of Window
          this.DataContext = this;
        }
      }
     
      public class items : ObservableCollection<item> { }
     
      public class item : INotifyPropertyChanged
      {
        public item(int v) { value = v; }
        private int _value;
        public int value
        {
          get { return _value; }
          set
          {
            _value = value;
            if (PropertyChanged != null)
              PropertyChanged(thisnew PropertyChangedEventArgs("value"));
          }
        }
        public event PropertyChangedEventHandler PropertyChanged;
      }

     

    下载:http://cid-51b2fdd068799d15.office.live.com/self.aspx/.Public/Samples%5E_2011/20110602%5E_Binding2DArrayInDataGrid.zip

     


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年6月1日 18:26
    版主
  • 感谢帮助!对我来说非常有价值

    2011年6月20日 1:35
  • Hi,Bob

    感谢您的帮助,我已经采用的您的方法!目前的需求是第二维的元素数量是一样的,但是一维和二维的个数是动态确定的,我使用了一个AutoGeneratingColumn事件,但是比较麻烦的是每个单元格可以根据值的不同变为不可用的(若值为0,此单元格变灰)。我打算用一个数据模板达到此目的,但是DataGrid显示出来有误。

    希望得到您进一步指点。谢谢!

    XAML:
    
    <Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
      <Window.Resources>
        <DataTemplate x:Key="CellTemplate">
           <TextBox Visibility="{Binding Visible}" Text="{Binding Value}"/>
         </DataTemplate>
    
      </Window.Resources>
      <Grid>
      <DataGrid x:Name="dg" Grid.Row="0" ItemsSource="{Binding CollectionSource}" >
      </DataGrid>   
     </Grid>
    </Window>

     

    namespace WpfApplication2
    {
     /// <summary>
     /// Interaction logic for MainWindow.xaml
     /// </summary>
     public partial class MainWindow : Window
     {
      public ObservableCollection<items> CollectionSource { get; set; }
    
      public MainWindow()
      {
       InitializeComponent();
    
        // For CollectionSource
       CollectionSource = new ObservableCollection<items>()
       {
        new items(){new item(0),new item(2),new item(3),new item(4),new item(5),new item(6),new item(7),new item(8),new item(0)},
        new items(){new item(11),new item(12),new item(13),new item(14),new item(15),new item(16),new item(17),new item(18),new item(19)},
        new items(){new item(21),new item(22),new item(23),new item(24),new item(25),new item(26),new item(27),new item(28),new item(29)},
        new items(){new item(31),new item(32),new item(33),new item(34),new item(35),new item(36),new item(37),new item(38),new item(39)},
        new items(){new item(0),new item(42),new item(43),new item(44),new item(45),new item(46),new item(47),new item(48),new item(0)},
    
       };
    
       // Set the DataContext of Window
       this.DataContext = this;
    
       this.dg.CanUserAddRows = false;
       this.dg.GridLinesVisibility = DataGridGridLinesVisibility.None;
    
       this.dg.SelectionUnit = DataGridSelectionUnit.Cell;
    
       this.dg.LoadingRow += new EventHandler<DataGridRowEventArgs>(dgData_LoadingRow);
    
       this.dg.AutoGeneratingColumn += new EventHandler<DataGridAutoGeneratingColumnEventArgs>(dgData_AutoGeneratingColumn);
    
       this.dg.AutoGeneratedColumns += new EventHandler(dgData_AutoGeneratedColumns);
      }
      void dgData_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
      {
         DataGridTemplateColumn column = new DataGridTemplateColumn();
        column.CellTemplate = (DataTemplate)Resources["CellTemplate"];
        e.Column = column;
          }
    
      void dgData_AutoGeneratedColumns(object sender, EventArgs e)
      {
        for (int i = 0; i < this.dg.Columns.Count; i++)
        {
          this.dg.Columns[i].Header = (i + 1).ToString();
    
        }
      }
    
    
      //配置datagrid
    
    
      void dgData_LoadingRow(object sender, DataGridRowEventArgs e)
      {
        e.Row.Header = (e.Row.GetIndex() + 1).ToString();
      }
     }
    
    
     public class items : ObservableCollection<item> { }
    
     public class item : INotifyPropertyChanged
     {
      public item(int v) { value = v; }
      private int _value;
      public int value
      {
       get { return _value; }
       set
       {
        _value = value;
        _visible = (this._value == 0) ? Visibility.Hidden : Visibility.Visible;
        if (PropertyChanged != null)
         PropertyChanged(this, new PropertyChangedEventArgs("value"));
       }
      }
    
      private Visibility _visible;
    
      public Visibility Visible
      {
        get { return _visible; }
        set 
        { 
          _visible = value;
          if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
        }
      }
    
      public event PropertyChangedEventHandler PropertyChanged;
     }
    }
    

    2011年6月20日 8:15
  • 有个错误,你是动态增加CellTemplate,但是你没有动态指定每个列要绑定item的索引。

    你应该动态生成DataTemplate 并且绑定是要带索引的:

    修改你的 AutoGeneratingColumn 事件Handler

     

        void dgData_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
          for (int columnIndex = 0; columnIndex < this.CollectionSource[0].Count; columnIndex++)
          {
            DataGridTemplateColumn column = new DataGridTemplateColumn();
            XmlTextReader sr = new XmlTextReader(
              new StringReader(
                "<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">" +
                  "<TextBox Visibility=\"{Binding [" + columnIndex + "].Visible}\" Text=\"{Binding [" + columnIndex + "].Value}\"/>" +
                "</DataTemplate>"));
     
            column.CellTemplate = (DataTemplate)XamlReader.Load(sr);
            (sender as DataGrid).Columns.Add(column);
          }
          e.Column = null;
        }
    Sincerely,

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年6月20日 10:52
    版主