声明性地在WPF中向网格添加行和控件

时间:2016-05-22 17:51:13

标签: c# wpf

嗯,我的last question没有得到任何回应,除了一个downvote,所以我打算分解这个问题并一次提出一个基本问题。

我有一个WPF应用程序,其中有一个Grid(不是DataGrid)。现在我想在运行时向它添加行。并且在每个行中都将是TextBox或Combobox之类的控件。我理解这可以通过RowDefinitions.Add(New RowDefinition())完成,然后向行中的每个单元格添加单独的控件,就像我们在WinForms中的TableLayoutPanel中所做的那样。但我正在寻找一种更优雅的解决方案,当点击按钮或触发事件时,所有带有事件处理程序的控件都将添加到Grid的新行中的相应单元格中。有没有简单的方法呢?

P.S。我还需要根据需要删除行,如果这是一个因素。删除的行并不总是最后一行。

1 个答案:

答案 0 :(得分:0)

通常情况下,最好使用DataGrid显示重复行的数据,而不是 一个网格。但是如果你有特殊的理由使用Grid,我已经使用Grid附加了一个代码示例,每行显示一个Textbox,一个ComboBox和一个DeleteButton。 “添加”按钮允许在底部添加新行,每行的DeleteButtons允许删除该行。

XAML:

<Window x:Class="GridAddRow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GridAddRow"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
  <DockPanel>
    <Grid Name="MainGrid" DockPanel.Dock="Top"/>
    <Button  DockPanel.Dock="Top" Name="AddButton" Content="Add"/>
    <Rectangle Fill="Gainsboro"/>
  </DockPanel>
</Window>

C#:

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace GridAddRow {

  public partial class MainWindow: Window {

    int textCol, comboBoxCol, buttonCol;

    public MainWindow() {
      InitializeComponent();

      //initialise MainGrid, i.e. define columns, could be done in XAML
      addCol(out textCol, new GridLength(100));
      addCol(out comboBoxCol, GridLength.Auto);
      addCol(out buttonCol, GridLength.Auto);

      //initialise grid content, usually read from a db
      addRow("Some Text", 1);
      addRow("Another String", 3);

      AddButton.Click += AddButton_Click;
    }

    private void addCol(out int textCol, GridLength gridLength) {
      textCol = MainGrid.ColumnDefinitions.Count;
      MainGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = gridLength });
    }

    List<TextBox> textBoxes = new List<TextBox>();
    List<ComboBox> comboBoxes = new List<ComboBox>();

    private void addRow(string textBoxString, int comboBoxIndex) {
      int rowId = MainGrid.RowDefinitions.Count;
      MainGrid.RowDefinitions.Add(new RowDefinition());

      TextBox textBox = new TextBox { Text = textBoxString };
      textBoxes.Add(textBox);
      addControl(textBox, rowId, textCol);
      textBox.TextChanged += TextBox_TextChanged;

      ComboBox comboBox = new ComboBox {SelectedIndex= comboBoxIndex };
      comboBox.Items.Add(new ComboBoxItem {Content="0" });
      comboBox.Items.Add(new ComboBoxItem { Content="1" });
      comboBox.Items.Add(new ComboBoxItem { Content="2" });
      comboBox.Items.Add(new ComboBoxItem { Content="3" });
      comboBoxes.Add(comboBox);
      addControl(comboBox, rowId, comboBoxCol);
      comboBox.SelectionChanged += ComboBox_SelectionChanged;

      Button deleteRowButton = new Button {Content = "Delete"};
      addControl(deleteRowButton, rowId, buttonCol);
      deleteRowButton.Click += DeleteRowButton_Click;
    }

    private void addControl(Control control, int rowId, int textCol) {
      control.Tag = rowId;
      MainGrid.Children.Add(control);
      Grid.SetRow(control, rowId);
      Grid.SetColumn(control, textCol);
    }

    private void TextBox_TextChanged(object sender, TextChangedEventArgs e) {
      TextBox textbox = (TextBox)sender;
      int rowid = (int)textbox.Tag;
      //do something here. 
    }

    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
      ComboBox comboBox = (ComboBox)sender;
      int rowid = (int)comboBox.Tag;
      //do something here. 
    }

    private void DeleteRowButton_Click(object sender, RoutedEventArgs e) {
      Button deleteButton = (Button)sender;
      int rowid = (int)deleteButton.Tag;
      MainGrid.Children.Remove(deleteButton);

      TextBox textbox = textBoxes[rowid];
      MainGrid.Children.Remove(textbox);
      textBoxes.RemoveAt(rowid);

      ComboBox comboBox = comboBoxes[rowid];
      MainGrid.Children.Remove(comboBox);
      comboBoxes.RemoveAt(rowid);
    }

    private void AddButton_Click(object sender, RoutedEventArgs e) {
      addRow("", 1);
    }
  }
}

说&#34;你应该使用MVVM&#34;基本上只是意味着你应该为你在Window中使用的每个控件(Textbox,Combobox)创建一个具有一个属性的类。使用要显示的数据创建该类的集合,然后将其绑定到DataGrid,DataGrid将显示数据并提供许多功能,您必须在使用Grid时自行编程。有关详细信息,请参阅我的文章:Guide to WPF DataGrid formatting using bindings