1

I have three textboxes. I need to add each value to the corresponding fields. Datagrid have headers "#, ProductName, ProductCode, Tax, Total"

WPF

                <DataGrid ItemsSource="{Binding dt}" x:Name="dgrdBilling" MinColumnWidth="100" Grid.Row="1" CanUserReorderColumns="False" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="Cell" Margin="1,0,-1,0">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="#" Width="25" CanUserResize="False" MinWidth="25"/>
                        <DataGridTextColumn Header="Name"/>
                        <!--<DataGridTextColumn Header="Name" Binding="{Binding Path=ProductName}"/>-->
                        <DataGridTextColumn Header="Code"/>
                        <DataGridTextColumn Header="Quantity"/>
                        <DataGridTextColumn Header="Price"/>
                        <DataGridTextColumn Header="Tax1"/>
                        <DataGridTextColumn Header="Tax2"/>
                        <DataGridTextColumn Header="Tax3"/>
                        <DataGridTextColumn Header="Total"/>
                    </DataGrid.Columns>
                </DataGrid>

Click Event of button to add data to datagrid

    private void btnAddProduct_Click(object sender, RoutedEventArgs e)
    {
        SqlCeCommand com = new SqlCeCommand("SELECT * FROM Products_Master WHERE ProductName =('" + txtAutoProductName.Text + "') OR ProductCode = ('" + txtProductCode.Text + "')", con);
        try
        {
            System.Windows.Controls.DataGrid dg = new System.Windows.Controls.DataGrid();
            SqlCeDataAdapter da = new SqlCeDataAdapter();
            BindingSource bSource = new BindingSource();
            DataTable dt = new DataTable();
            DataRow newRow = dt.NewRow();
            da.SelectCommand = com;
            da.Fill(dt);
            bSource.DataSource = dt;
            dg.Items.Add(txtAutoProductName.Text);
            dg.Items.Add(txtAutoProductCode.Text);
            dg.Items.Add(txtQuantity.Text);
            //dgrdBilling.ItemsSource = dt.DefaultView;
            //dgrdBilling.Items.Add(dg);
            da.Update(dt);
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message, System.Windows.Forms.Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
Kamal
  • 469
  • 2
  • 8
  • 19
  • You're creating one `DataGrid` in XAML, and another `DataGrid` in code-behind. Which one you want to be filled with data? – Dennis Oct 29 '13 at 06:09
  • ohh sorry. Is that what happening there. I don't know. I just need to add datarow wise after pressing the button each time. – Kamal Oct 29 '13 at 06:14
  • You shouldn't manipulate UI from code-behind in WPF. You should have a proper data type containing the `ProductName, ProductCode, Tax, Total` field, fill a collection of that type from your DB, and bind the `DataGrid` to that. – Omri Btian Oct 29 '13 at 06:24
  • BTW, You should alter your SQL tatement to use [Parameters](http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.parameters.aspx) to avoid SQL injection – Omri Btian Oct 29 '13 at 06:30
  • How is it done, to avoid SQL injection? – Kamal Oct 29 '13 at 06:31
  • Look at the link in my previous comment. There is a detailed example on the MSDN page. – Omri Btian Oct 29 '13 at 06:42
  • Are you using MVVM or not ? – Thilina H Oct 30 '13 at 05:37

2 Answers2

2

Seem like you confused a lot of stuff here.

First of all, you shouldn't manipulate UI Elements from code-behind in WPF. You should have a proper data type containing the ProductName, ProductCode, Tax, Total or any other fields you may want, fill a collection of that type, and bind THAT to the DataGrid.

public class Product
{
    public string ProductName { get; set; }

    public string ProductCode { get; set; }

    public int Tax { get; set; }

    public int Total { get; set; }
}

Store a collection of that class (preferably ObservableCollection that notifys the UI when it changes to make it update itself)

public ObservableCollection<Product> Products { get; set;}

Usually it should be done in different class that you set as the DataContext of the window (Known as ViewModel), But if you set it in the code-behind, you can just set the window's DataContext to itself. In window's constructor after InitializeComponents() add

DataContext = this

Now, create a Product with the relevant data and add it to the collection instead of directly to the grid:

        Product p = new Product
        {
            ProductName = txtAutoProductName.Text,
            ProductCode = txtAutoProductCode.Text
            // Fill in the rest of the properties as you want ...
        }
        Products.Add(p);

Finally, Alter your grid to look something like this:

<DataGrid ItemsSource="{Binding Products}" x:Name="dgrdBilling" MinColumnWidth="100" Grid.Row="1" CanUserReorderColumns="False" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="Cell" Margin="1,0,-1,0">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="#" Width="25" CanUserResize="False" MinWidth="25"/>
                    <DataGridTextColumn Header="Name" Binding="{Binding ProductName}"/>
                    <DataGridTextColumn Header="Code" Binding="{Binding ProductCode}"/>
                    <!-- rest of your columns ... -->
                </DataGrid.Columns>
            </DataGrid>

To are some links that can help you understand the concept better:

Transitioning from Windows Forms to WPF

http://www.codeproject.com/Articles/140621/WPF-Tutorial-Concept-Binding

Also you should look into the MVVM pattern which is considered the best practice when developing WPF application

Good luck

Community
  • 1
  • 1
Omri Btian
  • 6,499
  • 4
  • 39
  • 65
  • If you don't mind can u explain what "Products" means in – Kamal Oct 29 '13 at 07:09
  • The `ItemsSource` should be binded to a collection (a class that implements the [IEnumerable](http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx) interface). as you can see in my example, `Products` is actually property of type `ObservableCollection` in that class defined as `DataContext` (In this example, the same class where you handle the button's click event hence you set `DataContext = this`). The `DataGrid` Iterates the collection and add's each element as a row. this is why you should manipulate DATA (the collection) and let WPF do the rest of the work. – Omri Btian Oct 29 '13 at 07:15
  • Also, to make the `DataGrid` update each time we change it's underlying collection, we need to raise an event called `PropertyChanged` every time we change the colleciton. The reason I said "preferably ObservableCollection" is because it already implements this for us. – Omri Btian Oct 29 '13 at 07:18
  • "public ObservableCollection Products { get; set;}" It causes an error. The type or namespace name 'ObservableCollection' could not be found (are you missing a using directive or an assembly reference?) – Kamal Oct 29 '13 at 07:18
  • You need to add the following using statement `using System.Collections.ObjectModel;` – Omri Btian Oct 29 '13 at 07:18
  • I am getting an exception at Products.Add(p);. Object Reference not set to an instance of an object. – Kamal Oct 29 '13 at 07:25
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/40158/discussion-between-kamal-mohan-and-omribitan) – Kamal Oct 29 '13 at 07:27
  • @KaMaLMoHaN You need to initialize it first `Products = new ObservableCollection();` – Omri Btian Oct 29 '13 at 07:27
  • The datagrid is still blank. – Kamal Oct 29 '13 at 07:37
  • yes @Kamal is right, i still dont see the `DataGrid` – eqrakhattak Nov 28 '20 at 14:34
  • can anyone guide me why? – eqrakhattak Nov 29 '20 at 10:04
1

You're misunderstanding bindings in WPF and mixing WinForms and WPF binding approach.

First of all, DataGrid supports direct binding to a DataTable instance, so, it is enough to set DataGrid.ItemsSource to a DataTable:

<DataGrid ItemsSource="{Binding SomDataTable}">

The second, DataGrid by default can generate columns from DataTable schema. If you want to override this behavior, you should turn off column generation (this is done in your code), and, also, you should bind your columns with DataTable columns like this:

<DataGridTextColumn Header="MyHeader" Binding="{Binding MyDataTableColumnName}"/>

The third, you don't want to add a row to the DataGrid. You want to a row to the DataTable, so, your click handler should look like this:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        // ...
        dataTable.Rows.Add(/* ... */);
    }
Dennis
  • 37,026
  • 10
  • 82
  • 150