如何在Wpf中以编程方式在网格的行内创建网格

时间:2013-09-29 17:10:17

标签: c# .net wpf

我在WPF工作 - 我的应用程序中有button click event handler。当我点击按钮时,它的事件处理程序在网格中生成一个名为grids的新行。在这个新的行中,我想以编程方式添加另一个网格,以便在此行的网格中添加Label,Button和TextBox。 当我执行我的代码时,它只生成一个texboxes!标签和按钮显示一次!这里的代码和图片是:请随时询问我的查询是否不清楚!

 int r =0;
 private void button2_Click(object sender, RoutedEventArgs e)
    {
        TextEdit text1; Button button1; Grid grid1;
        grids.RowDefinitions.Add(new RowDefinition());
        text1 = new TextEdit();
        text1.SetValue(Grid.ColumnProperty, 1);
        text1.SetValue(Grid.RowProperty, r);
        button1 = new Button();
        button1.Content = "Left + " + r;
        button1.Click += new RoutedEventHandler(button1_Click);
        button1.SetValue(Grid.ColumnProperty, 1);
        button1.SetValue(Grid.RowProperty, r);
        grid1 = new Grid();
        grid1.SetValue(Grid.ColumnProperty, 1);
        grids.RowDefinitions.Add(new RowDefinition());
        grid1.SetValue(Grid.RowProperty, r);
        grids.Children.Add(button1);
        grids.Children.Add(text1);
        r = r + 1;
    }

enter image description here修改

 int r =0;
 private void button2_Click(object sender, RoutedEventArgs e)
  {
    db obj = new db();
    var query = from p in obj.TableA select p ;

  foreach(var a in query.ToList())
  {
    TextEdit text1; Button button1; Grid grid1;
    grids.RowDefinitions.Add(new RowDefinition());
    text1 = new TextEdit();
    text1.SetValue(Grid.ColumnProperty, 1);
    text1.SetValue(Grid.RowProperty, r);
    button1 = new Button();
    button1.Content = a.name;
    button1.Click += new RoutedEventHandler(button1_Click);
    button1.SetValue(Grid.ColumnProperty, 1);
    button1.SetValue(Grid.RowProperty, r);
    grid1 = new Grid();
    grid1.SetValue(Grid.ColumnProperty, 1);
    grids.RowDefinitions.Add(new RowDefinition());
    grid1.SetValue(Grid.RowProperty, r);
    grids.Children.Add(button1);
    grids.Children.Add(text1);
    r = r + 1;}
}

2 个答案:

答案 0 :(得分:21)

确定。删除所有代码并从头开始。

如果你正在使用WPF,你真的需要The WPF Mentality

作为一般规则,您几乎从不在WPF中的过程代码中创建或操作UI元素。 这就是XAML的用途。

这是在WPF中执行您所要求的正确方法(在完整的工作示例中):

<Window x:Class="MiscSamples.ItemsControlSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
        Title="ItemsControlSample" Height="300" Width="300">
    <DockPanel>
        <Button Content="Add New Row" Command="{Binding AddNewRowCommand}"
                DockPanel.Dock="Bottom"/>

        <ItemsControl ItemsSource="{Binding Data}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border  BorderBrush="Black" Background="Gainsboro" BorderThickness="1" Margin="2">
                        <!-- This is the Inner Grid for each element, which is represented in Brown color in your picture -->
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition/>
                                <ColumnDefinition Width=".2*"/>
                                <ColumnDefinition Width=".2*"/>
                            </Grid.ColumnDefinitions>

                            <Label Content="{Binding Label1Text}"
                                   Margin="2"/>

                            <Button Content="Button1" 
                                    Command="{Binding DataContext.Command1, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                                    CommandParameter="{Binding}"
                                    Grid.Column="1" Margin="2"/>

                            <Button Content="Button2" 
                                    Command="{Binding DataContext.Command2, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                                    CommandParameter="{Binding}"
                                    Grid.Column="2" Margin="2"/>

                            <dxe:TextEdit Text="{Binding Text}"
                                          Grid.Row="1" Grid.ColumnSpan="3"
                                          Margin="2"/>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <ScrollViewer CanContentScroll="True">
                        <ItemsPresenter/>
                    </ScrollViewer>
                </ControlTemplate>
            </ItemsControl.Template>

            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </DockPanel>
</Window>

代码背后:

public partial class ItemsControlSample : Window
{
    public ItemsControlSample()
    {
        InitializeComponent();
        DataContext = new ItemsControlSampleViewModel();
    }
}

视图模型:

public class ItemsControlSampleViewModel
{
    public ObservableCollection<ItemsControlSampleData> Data { get; set; }

    public Command AddNewRowCommand { get; set; }

    public Command<ItemsControlSampleData> Command1 { get; set; }

    public Command<ItemsControlSampleData> Command2 { get; set; }

    public ItemsControlSampleViewModel()
    {
        var sampledata = Enumerable.Range(0, 10)
                                   .Select(x => new ItemsControlSampleData()
                                                {
                                                    Label1Text = "Label1 " + x.ToString(),
                                                    Text = "Text" + x.ToString()
                                                });

        Data = new ObservableCollection<ItemsControlSampleData>(sampledata);
        AddNewRowCommand = new Command(AddNewRow);
        Command1 = new Command<ItemsControlSampleData>(ExecuteCommand1);
        Command2 = new Command<ItemsControlSampleData>(ExecuteCommand2);

    }

    private void AddNewRow()
    {
        Data.Add(new ItemsControlSampleData() {Label1Text = "Label 1 - New Row", Text = "New Row Text"});
    }

    private void ExecuteCommand1(ItemsControlSampleData data)
    {
        MessageBox.Show("Command1 - " + data.Label1Text);
    }

    private void ExecuteCommand2(ItemsControlSampleData data)
    {
        MessageBox.Show("Command2 - " + data.Label1Text);
    }
}

数据项:

public class ItemsControlSampleData
{
    public string Label1Text { get; set; }

    public string Text { get; set; }
}

助手班:

public class Command : ICommand
{
    public Action Action { get; set; }

    public string DisplayName { get; set; }

    public void Execute(object parameter)
    {
        if (Action != null)
            Action();
    }

    public bool CanExecute(object parameter)
    {
        return IsEnabled;
    }

    private bool _isEnabled = true;
    public bool IsEnabled
    {
        get { return _isEnabled; }
        set
        {
            _isEnabled = value;
            if (CanExecuteChanged != null)
                CanExecuteChanged(this, EventArgs.Empty);
        }
    }

    public event EventHandler CanExecuteChanged;

    public Command(Action action)
    {
        Action = action;
    }
}

public class Command<T>: ICommand
{
    public Action<T> Action { get; set; }

    public void Execute(object parameter)
    {
        if (Action != null && parameter is T)
            Action((T)parameter);
    }

    public bool CanExecute(object parameter)
    {
        return IsEnabled;
    }

    private bool _isEnabled = true;
    public bool IsEnabled
    {
        get { return _isEnabled; }
        set
        {
            _isEnabled = value;
            if (CanExecuteChanged != null)
                CanExecuteChanged(this, EventArgs.Empty);
        }
    }

    public event EventHandler CanExecuteChanged;

    public Command(Action<T> action)
    {
        Action = action;
    }
}

结果:

enter image description here

  • 请注意我不是在处理程序代码中处理UI,而是使用DataBinding简单,简单的属性。这就是你在WPF中编程的方式。这就是WPF的心态。
  • 我正在使用XAML中定义的ItemsControlDataTemplate让WPF为我的每个数据项创建UI。
  • 还要注意我的代码除了公开数据和定义可重用的Commands之外什么都不做,它们用作用户操作(如Button点击)的抽象。通过这种方式,您可以专注于编写业务逻辑,而不是如何使UI工作。
  • 使用RelativeSource绑定将每个项目内的按钮绑定到命令,以在Visual Tree中向上导航,并找到ItemsControl的DataContext,其中实际定义了命令。
  • 当您需要添加新项目时,只需向包含数据的ObservableCollection添加新项目,WPF会自动创建绑定到该项目的新UI元素。
  • 虽然这可能看起来像“代码太多”,但我在这里发布的大部分代码都是高度可重用的,可以在Generic ViewModel<T>中实现,然后可以为任何类型的数据项重用。 CommandCommand<T>也是可写入的可重用类,可以在任何MVVM框架中找到,例如PrismMVVM LightCaliburn.Micro
  • 这种方法在WPF中非常受欢迎,因为它在UI和业务逻辑之间实现了大量的可伸缩性和独立性,并且还实现了ViewModel的可测试性。
  • 我建议你阅读帖子中链接的所有资料,最重要的是Rachel的WPF心态和相关的博客文章。如果您需要进一步的帮助,请告诉我。
  • WPF Rocks 。只需将我的代码复制并粘贴到File -> New Project -> WPF Application中,然后自行查看结果。

答案 1 :(得分:6)

在xaml代码中代码背后实际上要容易得多..

我的Xaml代码:

<Window x:Class="WpfAddGridWithStackPanel.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 x:Name="Grid_Grid" Margin="0,0,0,32">

        <Grid>
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <Grid x:Name="Grid_Grid" Margin="0,0,0,32"/>
    </ScrollViewer>
    <Button x:Name="btn_Add" Height="32" DockPanel.Dock="Bottom" VerticalAlignment="Bottom" Content="Add New Row" Click="btn_Add_Click" Width="150" HorizontalAlignment="Left" UseLayoutRounding="True" />
    <Button x:Name="btn_Remove" Height="32" DockPanel.Dock="Bottom" VerticalAlignment="Bottom" Content="Remove last Row" Click="btn_Remove_Click" Width="150" HorizontalAlignment="Right" />
</Grid>
</Window>

代码背后:

public partial class MainWindow : Window
    {
        int num = 0;
        public MainWindow()
        {
            InitializeComponent();
        }

        void btn1_Click(object sender, RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        void btn2_Click(object sender, RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

        private void btn_Remove_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Grid_Grid.RowDefinitions.RemoveAt(Grid_Grid.RowDefinitions.Count - 1);
                Grid_Grid.Children.RemoveAt(Grid_Grid.Children.Count - 1);
                num--;
            }
            catch { }
        }

        private void btn_Add_Click(object sender, RoutedEventArgs e)
        {
            StackPanel stack = new StackPanel();
            DockPanel dock = new DockPanel();
            Label lbl = new Label();
            Button btn1 = new Button();
            Button btn2 = new Button();
            TextBox txt1 = new TextBox();

            stack.Children.Add(dock);
            stack.Children.Add(txt1);
            dock.Children.Add(lbl);
            dock.Children.Add(btn2);
            dock.Children.Add(btn1);

            #region StackPanel Properties
            stack.Background = Brushes.LightGray;
            #endregion

            #region DockPanel Content Properties
            lbl.Content = "Label " + (num + 1).ToString();
            lbl.Height = 32;
            lbl.Width = 100;
            lbl.FontSize = 12;
            lbl.SetValue(DockPanel.DockProperty, Dock.Left);
            lbl.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;

            btn1.Content = "Butten 1";
            btn1.Height = 32;
            btn1.Width = 100;
            btn1.FontSize = 12;
            btn1.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
            btn1.SetValue(DockPanel.DockProperty, Dock.Right);
            btn1.Click += new RoutedEventHandler(btn1_Click);

            btn2.Content = "Butten 2";
            btn2.Height = 32;
            btn2.Width = 100;
            btn2.FontSize = 12;
            btn2.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
            btn2.SetValue(DockPanel.DockProperty, Dock.Right);
            btn2.Click += new RoutedEventHandler(btn2_Click);
            #endregion

            #region TextBox Properties
            txt1.Text = "Text " + (num + 1).ToString();
            txt1.Height = 32;
            txt1.Width = double.NaN;
            txt1.FontSize = 12;
            txt1.Padding = new Thickness(0, 7, 0, 7);
            #endregion

            Grid_Grid.RowDefinitions.Add(new RowDefinition());
            Grid_Grid.RowDefinitions[num].Height = new GridLength(66, GridUnitType.Pixel);
            Grid_Grid.Children.Add(stack);
            stack.SetValue(Grid.RowProperty, num);
            num++;
        }
    }