使用C#在每一行动态添加按钮到ListView

5

我有一个ListView,需要显示从数据库表中获取的所有行。同时,每行还要有两个编辑和删除按钮。由于我是初学者,所以在XAML中尝试了以下代码-

<ListView Height="352" HorizontalAlignment="Left" Margin="20,90,0,0" Name="Tab1lstProductCategories" VerticalAlignment="Top" Width="1008">
                        <ListView.View>
                            <GridView>
                                <GridViewColumn Header="Category Name" DisplayMemberBinding="{Binding Col1}" Width="200"/>
                                <GridViewColumn Header="Created Date" DisplayMemberBinding="{Binding Col2}" Width="200"/>
                                <GridViewColumn Header="Last Updated" DisplayMemberBinding="{Binding Col3}" Width="200"/>
                                <GridViewColumn Header="Edit" Width="200">
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <Button Content="Edit" Click="EditCategory" CommandParameter="{Binding Id}"/>
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>
                                <GridViewColumn Header="Delete" Width="200">
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <Button Content="Delete" Click="DeleteCategory"/>
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>
                            </GridView>
                        </ListView.View>
                    </ListView>

我使用C#编写了-

 DataTable dt=db.Select("select * from ProductCategories");
           for (int i = 0; i < dt.Rows.Count; i++)
        {
            //Button edit, delete;
            //edit = new Button();
            //edit.Content="Edit";
            //edit.Click += EditCategory;
            //delete= new Button();
            //delete.Content="Delete";
            //delete.Click += DeleteCategory;
            //edit.CommandParameter = dt.Rows[i]["Id"];
            //delete.CommandParameter = dt.Rows[i]["Id"];
            Tab1lstProductCategories.Items.Add(new { Col1 = dt.Rows[i]["CategoryName"], Col2 = dt.Rows[i]["CreatedDate"], Col3=dt.Rows[i]["LastUpdated"]});                
        }



private void EditCategory(object sender, RoutedEventArgs e)
        {
            Button b=sender as Button;
            MessageBox.Show(b.CommandParameter.ToString());
        }

    private void DeleteCategory(object sender, RoutedEventArgs e)
    {
    }

我得到的结果是- 在此输入图像描述 我想要一个按钮放在那里,请帮忙。

1
在WPF中,不要在过程式代码中创建或操作UI元素。这就是XAML的作用。您正在寻找一个“CellTemplate”。 - Federico Berasategui
当没有指定 DataTemplate 时,绑定将自动使用 ToString() 方法来显示内容。请使用 CellTemplate 来解决此问题。 - Omri Btian
人们应该停止直接将UI绑定到数据库。 - Omri Btian
1
天哪,你为什么要绑定到匿名类型?创建一个适当的数据模型,或者使用 ORM。 - Federico Berasategui
1个回答

21

好的,我看到你的代码存在几个问题。

1)像@HighCore建议的那样,你真的应该创建一个适当的数据类型。根据我对你的代码的理解,它应该类似于这样:

public class ProductCategory
{
    public int Id { get; set; }

    public string CategoryName { get; set; }

    public DateTime CreatedDate { get; set; }

    public DateTime LastUpdated { get; set; }
}

那么,创建一个ProductCategory集合,而不是直接添加匿名类型。

DataTable dt=db.Select("select * from ProductCategories");

// Create a collection for your types
ObservableCollection<ProductCategory> list = new ObservableCollection<ProductCategory>();

for (int i = 0; i < dt.Rows.Count; i++)
{
    ProductCategory productCategory = new ProductCategory
    {
        // Casting might be needed here depending on your data types ...
        Id = dt.Rows[i]["Id"],
        CategoryName = dt.Rows[i]["CategoryName"],
        CreatedDate = dt.Rows[i]["CreatedDate"],
        LastUpdated = dt.Rows[i]["LastUpdated"]
    };

    list.Add(productCategory);
}

2) 您正在直接向 ListView 中添加项,这是错误的。您应该将集合设置为ListViewItemsSource

Tab1lstProductCategories.ItemsSource = list;

3)通过使用CellTemplate来实现在XAML中所需的ListView外观,并将DisplayMemberBinding绑定到相应的属性后,您可以通过默认的{Binding}表达式绑定CommandParameter,这将使命令参数成为所代表的ProductCategory项。

    <ListView Height="352" HorizontalAlignment="Left" Margin="20,90,0,0" Name="Tab1lstProductCategories" VerticalAlignment="Top" Width="1008">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Category Name" DisplayMemberBinding="{Binding CategoryName}" Width="200"/>
                <GridViewColumn Header="Created Date" DisplayMemberBinding="{Binding CreatedDate}" Width="200"/>
                <GridViewColumn Header="Last Updated" DisplayMemberBinding="{Binding LastUpdated}" Width="200"/>
                <GridViewColumn Header="Edit" Width="200">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="Edit" Click="EditCategory" CommandParameter="{Binding}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="Delete" Width="200">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="Delete" Click="DeleteCategory" CommandParameter="{Binding}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>

从事件处理程序 - EditCategoryDeleteCategory中,您可以提取ProductCategory的ID

private void EditCategory(object sender, RoutedEventArgs e)
{
    Button b=sender as Button;
    ProductCategory productCategory = b.CommandParameter as ProductCategory;
    MessageBox.Show(productCategory.Id);
}

这应该足以使您的代码正常运行,但我还想提出几个其他要点:

a. 您应该高度考虑使用MVVM模式。这意味着不在代码后台使用事件处理程序,而是改用Commands,并且使用CommandParameter的原始用法。

b. 考虑使用一些ORM框架,而不是直接将数据库绑定到UI上。这会创建紧密耦合,使您的代码可重用性和灵活性降低。

希望有所帮助。


我该如何为每个按钮的不同行添加不同的ID? - Prateek Shukla
Id是我在表格中确切的名称,应该与之绑定。我已经按照您的建议添加了CommandParameter,并实现了EditCategory函数,如下所示-private void EditCategory(object sender, RoutedEventArgs e) { Button b=sender as Button; MessageBox.Show(b.CommandParameter.ToString()); }但是,一旦进入此函数,就会引发NullPointerException异常。为什么会发生这种情况? - Prateek Shukla
@PrateekShukla 对我来说它有效。你的代码肯定有其他问题。请更新你的问题并附上更新后的代码,这样我们就可以检查一下了。 - Omri Btian
很棒的解决方案。我所缺少的是在哪里修改这些按钮的属性部分。目前只有一个与ID绑定的通用绑定。但是,我如何从代码中设置网格中按钮的属性呢? - Tony B
嗨@OmriBtian,太棒了!这对我完美地奏效了,只需要知道是否有可能,如果类的任何值实时更改,则listview会显示这种更改,只需更改类中的值即可。 - Apalabrados

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接