5

I have a ListView in which I have to show all rows fetched from my database table. Again I have to give two edit and delete buttons in each row. As I am beginner for the same, I tried the following code in 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>

And in C# I Wrote-

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

I got the result as- enter image description here

I want button over there, Please help me out.

4
  • 1
    Don't create or manipulate UI elements in procedural code in WPF. That's what XAML is for. You're looking for a CellTemplate. Commented Oct 14, 2013 at 14:00
  • Bindings will automatically use ToString() method to display a content when not given a certain DataTemplate. Use a CellTemplate for this. Commented Oct 14, 2013 at 14:00
  • People should stop binding UI directly to database ... Commented Oct 14, 2013 at 14:08
  • 1
    OMG Why in the world are you binding to an anonymous type?? Create a proper data model instead, or use an ORM. Commented Oct 14, 2013 at 14:46

1 Answer 1

21

Ok, so I see a couple of issues with your code.

1) You really should create a proper datatype like @HighCore suggested. Looking at your code I assume it will look something like this:

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

    public string CategoryName { get; set; }

    public DateTime CreatedDate { get; set; }

    public DateTime LastUpdated { get; set; }
}

Then create a collection of ProductCategory instead of directly adding anonymous types

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) You are directly adding item's to the ListView which is wrong. What you should be doing is set your collection to be the ItemsSource of your ListView.

Tab1lstProductCategories.ItemsSource = list;

3) After using CellTemplate to achieve the ListView wanted look through xaml and changing the DisplayMemberBinding binding to the appropriate properties, you can bind the CommandParameter through the default {Binding} expression which will set the command parameter to be the ProductCategory item it represents.

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

From the event handlers - EditCategory and DeleteCategory, you can extract the Id of the ProductCategory

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

This should be sufficient to make your code work, but there are several other points I'd like to make

a. You should highly consider using MVVM pattern. this will mean not using event handlers in code behind but using Commands instead, and use CommandParameter the way it was originally intended to be used.

b. Consider some ORM framework instead of binding the database directly to your UI. this create incredibly tight coupling which will make your code a lot less reusable, and flexible.

Hope this helps

Sign up to request clarification or add additional context in comments.

5 Comments

How I will add different IDs for different rows for each button?
Id is the exact name that I have in my table and supposed to bind with it. I have added CommandParameter as you suggested and implemented the EditCategory function as- private void EditCategory(object sender, RoutedEventArgs e) { Button b=sender as Button; MessageBox.Show(b.CommandParameter.ToString()); } But NullPointerException raised as soon as I entered in this function. Why it is happening?
@PrateekShukla it works for me. It must be something else wrong with your code. Update your question with the updated code so we can check it out
great solution. What i am missing is the part, where to modify the properties of these buttons. currently there's "only" a general binding with the id. but how can i set properties from the code to the entry of the button in the grid?
Hi @OmriBtian, fantastic solution! It works for me perfectly, just need to know if there is any possiblity that if any value from a class change in real time, the listview shows such change, only changing the value in the class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.