How do I correctly use the selected items property of a datagrid following mvvm?

don bradman 621 Reputation points
2022-08-30T01:01:09.71+00:00

I have a couple of datagrid's in my WPF app like

                        <DataGrid ItemsSource="{Binding FilteredBills}" AutoGenerateColumns="False"   
                                              IsReadOnly="True"  
                                              SelectionUnit="FullRow"  
                                              HeadersVisibility="Column"  
                                              Name="IMPGrid">  
                            <DataGrid.Columns>  
                                <DataGridTextColumn  
                                                Header="Bill No."  
                                                Binding="{Binding Path=BillNo, Mode=OneWay}"  
                                                Width="275"  
                                                IsReadOnly="True" />  
                                <DataGridTextColumn  
                                                Header="Bill Date"  
                                                Binding="{Binding Path=BillDt, Mode=OneWay}"  
                                                Width="75"  
                                                IsReadOnly="True" />  
                                <DataGridTextColumn  
                                                Header="Amount"  
                                                Binding="{Binding Path=Amt, StringFormat=N2, Mode=OneWay}"  
                                                Width="75"  
                                                IsReadOnly="True" />  
                            </DataGrid.Columns>  
                        </DataGrid>  
                        <DataGrid ItemsSource="{Binding AdjBills}" AutoGenerateColumns="False"  
                                              SelectionUnit="FullRow"  
                                              HeadersVisibility="Column"  
                                              Name="EXPGrid">  
                            <DataGrid.Columns>  
                                <DataGridTextColumn  
                                                Header="CNDN No."  
                                                Binding="{Binding Path=CndnNo, Mode=OneWay}"  
                                                Width="275"  
                                                IsReadOnly="True" />  
                                <DataGridTextColumn  
                                                Header="Date"  
                                                Binding="{Binding Path=Date, Mode=OneWay}"  
                                                Width="275"  
                                                IsReadOnly="True" />  
                                <DataGridTextColumn  
                                                Header="Amount"  
                                                Binding="{Binding Path=Value, Mode=OneWay}"  
                                                Width="275"  
                                                IsReadOnly="True" />  
                            </DataGrid.Columns>  
                        </DataGrid>  

The properties representing both the datagrid's columns reside in the same class

public class Bills : ViewModelBase  
    {  
        ...  
        private string _billNo;  
        public string BillNo  
        {  
            get  
            {  
                return _billNo;  
            }  
            set  
            {  
                SetValue(ref _billNo, value);  
            }  
        }  


        private string _billDt;  
        public string BillDt  
        {  
            get  
            {  
                return _billDt;  
            }  
            set  
            {  
                SetValue(ref _billDt, value);  
            }  
        }  

        ...  

        private double _value;  
        public double Value  
        {  
            get  
            {  
                return _value;  
            }  
            set  
            {  
                SetValue(ref _value, value);  
            }  
        }  

    }  

Now, what I'm trying to do is when I selected rows from both the datagrid's and hit the Preview button like this it should generate a PDF like this and if I choose only the first datagrid rows like this it should generate a PDF like this

Previously when I did not use the MVVM pattern I would use these helper classes (using itext5), call it in the button click event like invoice.GenerateDocument(filePath, infoText, lblCity, billsGrid, adjGrid); and it would work fine but now when I try to use it in my current app it is showing error

System.Exception: 'Unable to cast object of type 'DG2PDF.Bills' to type 'System.Data.DataRowView'.'

in the line foreach (DataRowView row in gridView.SelectedItems) of the below section

            foreach (DataRowView row in gridView.SelectedItems)  
            {  

                for (int x = 0; x < 3; x++)  
                {  
                    table.AddCell(new iTextSharp.text.Phrase(row.Row.ItemArray[x].ToString()));  
                }  
                _rowNumber++;  

            }  

If I change the foreach loop to foreach (Bills bill in gridView.SelectedItems) then I would have to hardcode the properties like table.AddCell(new iTextSharp.text.Phrase(bill.BillNo.ToString())); which is a problem as the gridView represents both datagrid's and their properties/columns are different.

How do I fix this ?

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,670 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,233 questions
{count} votes

Accepted answer
  1. Jiale Xue - MSFT 31,821 Reputation points Microsoft Vendor
    2022-09-09T09:48:29.38+00:00

    Hi @don bradman ,

    I added the data table without reproducing your problem, I added AddTable1 and GenerateTable1 and used GenerateTable1 to generate the second table in the preview.

    Write a separate method for the second table:

    GenerateTable1(document, creditNotesDataGrid, totalCreditNotes, "Less Credit Note/Debit Note", BaseColor.WHITE, BaseColor.WHITE);  
      
    private iTextSharp.text.Document GenerateTable1(iTextSharp.text.Document document, DataGrid gridView, decimal total, string headerText, BaseColor primaryHeaderBackgroundColor, BaseColor secondaryHeaderBackgroundColor)  
            {  
                if (gridView.SelectedItems.Count > 0)  
                {  
                    var columnsCount = gridView.Columns.Count;  
      
      
                   // Generate bills table  
                    return document  
                        .AddTable(columnsCount, table =>  
                        {  
                            table.AddPhrase(headerText, _tableHeaderFont, (cell, phrase) =>  
                            {  
                                cell.BackgroundColor = primaryHeaderBackgroundColor;  
                                cell.Colspan = columnsCount;  
                                cell.HorizontalAlignment = (int)Alignment.Center;  
                            });  
                        })  
                        .AddTable1(gridView, _tableHeaderFont, secondaryHeaderBackgroundColor, _helveticaFontSamllStandard)  
                        .AddTable(columnsCount, table =>  
                        {  
                            table  
                                .AddEmptyCell(columnsCount - 1)  
                                .AddStrongUnderlinedPhrase(total.ToDefaultStringFormat(), _tableHeaderFont);  
                        });  
      
      
      
               }  
               return document;  
            }  
    
    
    public static iTextSharp.text.Document AddTable1(this iTextSharp.text.Document document, DataGrid gridView, iTextSharp.text.Font headerFont, BaseColor headerBackgroundColor, iTextSharp.text.Font bodyFont)  
            {  
                var table = new iTextSharp.text.pdf.PdfPTable(gridView.Columns.Count)  
                {  
                    WidthPercentage = 75  
                };  
               table.DefaultCell.Padding = 3;  
               table.HorizontalAlignment = Element.ALIGN_CENTER;  
               foreach (DataGridColumn column in gridView.Columns)  
                {  
                    var cell = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(column.Header.ToString(), headerFont))  
                    {  
                        BackgroundColor = headerBackgroundColor  
                    };  
      
                   table.AddCell(cell);  
                }  
      
      
                foreach (Bills bill in gridView.SelectedItems)  
                {  
                    if (bill != null)  
                    {  
                        table.AddCell(new iTextSharp.text.Phrase(bill.CndnNo.ToString()));  
                        table.AddCell(new iTextSharp.text.Phrase(bill.Date.ToString()));  
                        table.AddCell(new iTextSharp.text.Phrase(bill.Value.ToString()));  
                    }  
      
      
      
               }  
                document.Add(table);  
                return document;  
            }  
    

    Then add it to The GenerateTable:

    // Generate body's paragraph  
    document.AddParagraph(bodyStartParagraph, _timesRomanNormal, Alignment.Left);  
      
    // Generate bills table  
    GenerateTable(document, billsDataGrid, totalBills, customerName, new BaseColor(255, 255, 30), new BaseColor(137, 220, 165));  
      
    // Generate credits table  
    GenerateTable1(document, creditNotesDataGrid, totalCreditNotes, "Less Credit Note/Debit Note", BaseColor.WHITE, BaseColor.WHITE);  
    

    239419-image.png

    Best Regards,
    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

0 additional answers

Sort by: Most helpful