System.NullReferenceException in Datagrid.Items (export DataGrid.Items into PDF), in WPF (by C#)

رضا جافری 1,296 Reputation points
2022-01-27T15:34:51.433+00:00

First and foremost, I apologize for my grammatical errors; my first language is Persian (Iran).
I want to display DataGrid as a table in PDF through the following codes and DataGrid has 10 columns, there is no problem when I add 8 rows but when I add 10 rows or more I get the following error:
System.NullReferenceException: 'Object reference not set to an instance of an object.' (Line 106 in C# codes)
169143-pdf.jpg
XAML codes:

<Window x:Class="Library.BillWindow"  
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"  
    xmlns:local="clr-namespace:Library"  
    mc:Ignorable="d"  
    Title="Bill" Loaded="Window_Loaded" Height="600" Width="800" Background="Transparent" FontSize="13" WindowStyle="None" AllowsTransparency="True">  
<Window.DataContext>  
    <local:ViewModel/>  
</Window.DataContext>  
<Grid>  
    <GroupBox x:Name="Products_Services_GroupBox" Header="Products/Services" Height="246" Width="772" Background="Transparent" HorizontalAlignment="Left" VerticalAlignment="Top" Visibility="Visible" Margin="14,292,0,0">  
        <GroupBox.Style>  
            <Style TargetType="{x:Type GroupBox}">  
                <Setter Property="BorderBrush" Value="DarkGray"/>  
                <Setter Property="BorderThickness" Value="1"/>  
                <Setter Property="Template">  
                    <Setter.Value>  
                        <ControlTemplate TargetType="{x:Type GroupBox}">  
                            <Grid SnapsToDevicePixels="true">  
                                <Grid.ColumnDefinitions>  
                                    <ColumnDefinition Width="*"/>  
                                    <ColumnDefinition Width="*"/>  
                                    <ColumnDefinition Width="*"/>  
                                    <ColumnDefinition Width="*"/>  
                                </Grid.ColumnDefinitions>  
                                <Grid.RowDefinitions>  
                                    <RowDefinition Height="*"/>  
                                    <RowDefinition Height="*"/>  
                                    <RowDefinition Height="*"/>  
                                    <RowDefinition Height="*"/>  
                                </Grid.RowDefinitions>  
                                <Border BorderBrush="DarkGray"   
                                BorderThickness="1"  
                                CornerRadius="9"  
                                Grid.ColumnSpan="4"   
                                Grid.RowSpan="4">  
                                    <Border.OpacityMask>  
                                        <MultiBinding ConverterParameter="9">  
                                            <MultiBinding.Converter>  
                                                <BorderGapMaskConverter/>  
                                            </MultiBinding.Converter>  
                                            <Binding ElementName="Header" Path="ActualWidth"/>  
                                            <Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/>  
                                            <Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}"/>  
                                        </MultiBinding>  
                                    </Border.OpacityMask>  
                                </Border>  
                                <Border x:Name="Header" Grid.RowSpan="1" Grid.ColumnSpan="4"  Margin="9,-9.5,0,0" HorizontalAlignment="Left" VerticalAlignment="Top">  
                                    <ContentPresenter  ContentSource="Header"  
                                              RecognizesAccessKey="True"   
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>  
                                </Border>  
                                <ContentPresenter  Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"   
                                          Margin="{TemplateBinding Padding}"  
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>  
                            </Grid>  
                        </ControlTemplate>  
                    </Setter.Value>  
                </Setter>  
            </Style>  
        </GroupBox.Style>  
        <ItemsControl x:Name="BillItemsControl" Width="772" Margin="-193,-61,-193,-121">  
            <Grid Height="244">  
                <DataGrid x:Name="BillDataGrid" HeadersVisibility="Column" CanUserAddRows="False" CanUserDeleteRows="False" EnableRowVirtualization="True" AutoGenerateColumns="False" HorizontalAlignment="Left" VerticalAlignment="Top" Height="190" Width="758" Margin="7,12,0,0">  
                    <i:Interaction.Behaviors>  
                        <local:DataGridBehavior/>  
                    </i:Interaction.Behaviors>  
                    <DataGrid.Columns>  
                        <DataGridTextColumn x:Name="NO" Binding="{Binding NO}" Width="SizeToHeader"/>  
                        <DataGridTextColumn x:Name="ID_Serial" Binding="{Binding ID_Serial}" Width="SizeToHeader"/>  
                        <DataGridTextColumn x:Name="ProductsOrServicesDescription" Binding="{Binding ProductsOrServicesDescription}" Width="115"/>  
                        <DataGridTextColumn x:Name="Quantity" Binding="{Binding Quantity}" Width="SizeToHeader"/>  
                        <DataGridTextColumn x:Name="UnitOfMeasurement" Binding="{Binding UnitOfMeasurement}" Width="SizeToHeader"/>  
                        <DataGridTextColumn x:Name="UnitPrice" Binding="{Binding UnitPrice}" Width="SizeToHeader"/>  
                        <DataGridTextColumn x:Name="Discount" Binding="{Binding Discount}" Width="SizeToHeader"/>  
                        <DataGridTextColumn x:Name="TaxDutyVat" Binding="{Binding TaxDutyVat}" Width="SizeToHeader"/>  
                        <DataGridTextColumn x:Name="GuaranteeOrWarrantyPeriod" Binding="{Binding GuaranteeOrWarrantyPeriod}" Width="SizeToHeader"/>  
                        <DataGridTextColumn x:Name="TotalAmount" Binding="{Binding TotalAmount}" Width="SizeToHeader"/>  
                    </DataGrid.Columns>  
                </DataGrid>  
                <Button Name="AddNewRow_Button" Command="{Binding}" CommandParameter="AddNewRow" MouseEnter="AddNewRow_Button_MouseEnter" GotFocus="AddNewRow_Button_GotFocus" HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Width="160" Cursor="Hand" Margin="7,208,0,0"/>  
                <Button Name="DeleteSelectedRows_Button" Command="{Binding}" CommandParameter="DeleteSelectedRows" MouseEnter="DeleteSelectedRows_Button_MouseEnter" GotFocus="DeleteSelectedRows_Button_GotFocus" HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Width="160" Cursor="Hand" Margin="174,208,0,0"/>  
                <Button Name="CalculateTotalAmount_Button" PreviewMouseLeftButtonDown="CalculateTotalAmount_Button_PreviewMouseLeftButtonDown" MouseEnter="CalculateTotalAmount_Button_MouseEnter" GotFocus="CalculateTotalAmount_Button_GotFocus" HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Width="160" Cursor="Hand" Margin="341,208,0,0"/>  
            </Grid>  
        </ItemsControl>  
    </GroupBox>  
</Grid>  
</Window>  

C# codes:
I can add a blank row to DataGrid and also delete one or more rows via the ViewModel class:

using iTextSharp.text;  
using iTextSharp.text.pdf;  
using System.Runtime.InteropServices;  
using System.Windows.Interactivity;  
public class ViewModel : ICommand  
{  
    public DataGrid BillDataGrid { get; set; }  
    int NO;  
    private struct DefaultRow  
    {  
        public string NO { get; set; }  
        public string ID_Serial { get; set; }  
        public string ProductsOrServicesDescription { get; set; }  
        public string Quantity { get; set; }  
        public string UnitOfMeasurement { get; set; }  
        public string UnitPrice { get; set; }  
        public string Discount { get; set; }  
        public string TaxDutyVat { get; set; }  
        public string GuaranteeOrWarrantyPeriod { get; set; }  
        public string TotalAmount { get; set; }  
    }  
    private void AddBlankRow()  
    {  
        List<object> DefaultRow = new List<object>();  
        DefaultRow DR = new DefaultRow();  
        DR.NO = (++NO).ToString();  
        DR.ID_Serial = "";  
        DR.ProductsOrServicesDescription = "";  
        DR.Quantity = "";  
        DR.UnitOfMeasurement = "";  
        DR.UnitPrice = "";  
        DR.Discount = "";  
        DR.TaxDutyVat = "";  
        DR.GuaranteeOrWarrantyPeriod = "";  
        DR.TotalAmount = "";  
        for (int i = 0; i < BillDataGrid.Items.Count; i++)  
        {  
            DefaultRow.Add(BillDataGrid.Items[i]);  
        }  
        DefaultRow.Add(DR);  
        BillDataGrid.ItemsSource = DefaultRow;  
    }  
    private void DeleteSelectedRows()  
    {  
        switch (BillDataGrid.SelectedItems.Count > 0)  
        {  
            case true:  
                List<object> DefaultRow = new List<object>();  
                for (int i = 0; i < BillDataGrid.Items.Count; i++)  
                {  
                    DefaultRow.Add(BillDataGrid.Items[i]);  
                }  
                foreach (DefaultRow Item in BillDataGrid.SelectedItems)  
                {  
                    DefaultRow.Remove(Item);  
                }  
                BillDataGrid.ItemsSource = DefaultRow;  
                break;  
        }  
    }  
    public event EventHandler CanExecuteChanged;  
    public bool CanExecute(object parameter) => true;  
    public void Execute(object parameter)  
    {  
        switch (parameter.ToString())  
        {  
            case "AddNewRow":  
                AddBlankRow();  
                break;  
            case "DeleteSelectedRows":  
                DeleteSelectedRows();  
                break;  
        }  
    }  
}  
public class DataGridBehavior : Behavior<DataGrid>  
{  
    protected override void OnAttached() =>  
      AssociatedObject.Loaded += (s, e) =>  
      ((ViewModel)AssociatedObject.DataContext).BillDataGrid = AssociatedObject;  
}  
public partial class BillWindow : Window  
{  
    public void ExportLTR(DataGrid dataGrid)  
    {  
        Document Doc = new Document(PageSize.A4, 10f, 10f, 27f, 14f);  
        PdfWriter PDF_Writer = PdfWriter.GetInstance(Doc, new FileStream((Path + @"\Invoice.pdf"), FileMode.Create));  
        Doc.Open();  
        PDF_Writer.RunDirection = PdfWriter.RUN_DIRECTION_LTR;  
        BaseFont Base_Font = BaseFont.CreateFont(System.Windows.Forms.Application.StartupPath + @"\Font Collection\Roboto.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);  
        Font DT_Font = new Font(Base_Font, 8);  
        PdfPTable PDF_Table = new PdfPTable(dataGrid.Columns.Count);  
        PDF_Table.RunDirection = PdfWriter.RUN_DIRECTION_LTR;  
        PDF_Table.WidthPercentage = 100;  
        PdfPCell Cell = new PdfPCell();  
        for (byte i = 0; i < dataGrid.Columns.Count; i++)  
        {  
            Cell.Colspan = dataGrid.Columns[i].Header.ToString().Count();  
            PDF_Table.AddCell(new Phrase(dataGrid.Columns[i].Header.ToString(), DT_Font));  
        }  
        DT_Font.Size = 9;  
        for (int i = 0; i < dataGrid.Items.Count; i++)  
        {  
            for (byte j = 0; j <= dataGrid.Columns.Count - 1; j++)  
            {  
                PDF_Table.AddCell(new Phrase((dataGrid.Columns[j].GetCellContent(dataGrid.Items[i]) as TextBlock).Text, DT_Font));  
            }  
        }  
        Doc.Add(PDF_Table);  
        Doc.Close();  
    }  
    private void Reporting_Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)  
    {  
        ExportLTR(BillDataGrid);  
    }  
}  

Thanks

Developer technologies | Windows Presentation Foundation
Developer technologies | XAML
Developer technologies | XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
Developer technologies | C#
Developer technologies | 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.
{count} votes

Answer accepted by question author
  1. Peter Fleischer (former MVP) 19,341 Reputation points
    2022-01-29T17:08:28.637+00:00

    Hi Reza,
    your code read only the showed TextBlocks (Visual Tree). I recommend you to use binded collection and read values from this collection.

    Try following code:

           var itemSource = dataGrid.ItemsSource as List<object>;
           for (int i = 0; i < dataGrid.Items.Count; i++)
           {
             var data = (DefaultRow)itemSource[i];
             for (int j = 0; j < dataGrid.Columns.Count; j++)
             {
               string value="";
               switch (j)
               {
                 case 0: value = data.NO; break;
     ....
                 case 9: value = data.ID_Serial; break;
                 default:
                   break;
               }
               PDF_Table.AddCell(new Phrase(value, DT_Font));
             }
           }
    
    1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. AgaveJoe 30,406 Reputation points
    2022-01-27T16:51:56.453+00:00

    The System.NullReferenceException is the most common exception is programming. It means the code tries to access members of a type but the type was never created. It's null. Or really, referencing the null type.

    The best way to fix a null exception is to use the Visual Studio debugger to find the null type. Once you find the null type then it is usually pretty easy to figure out why the type is null.

    https://learn.microsoft.com/en-us/visualstudio/debugger/debugger-feature-tour?view=vs-2022

    Line 106 is...

    PDF_Table.AddCell(new Phrase((dataGrid.Columns[j].GetCellContent(dataGrid.Items[i]) as TextBlock).Text, DT_Font));  
    

    If the results of GetCellContent() is null then the code is essentially doing this...

    null.Text  
    

    The null reference does not have a Text member.


  2. Peter Fleischer (former MVP) 19,341 Reputation points
    2022-01-28T13:28:08.997+00:00

    Hi Reza,
    change your code (to try null):

         for (int i = 0; i < dataGrid.Items.Count; i++)
         {
             for (byte j = 0; j <= dataGrid.Columns.Count - 1; j++)
             {
                 var tb = dataGrid.Columns[j].GetCellContent(dataGrid.Items[i]) as TextBlock;
                 PDF_Table.AddCell(new Phrase((tb == null)?"":tb.Text, DT_Font));
             }
         }
    

  3. رضا جافری 1,296 Reputation points
    2022-01-30T12:35:30.133+00:00

    Peter Fleischer's completed codes:

                var ItemsSource = dataGrid.ItemsSource as List<object>;  
                string Value = "";  
                for (int i = 0; i < dataGrid.Items.Count; i++)  
                {  
                    var Data = (ViewModel.DefaultRow)ItemsSource[i];  
                    for (byte j = 0; j < dataGrid.Columns.Count; j++)  
                    {  
                        switch(j)  
                        {  
                            case 0:  
                                Value = Data.NO;  
                                break;  
                            case 1:  
                                Value = Data.ID_Serial;  
                                break;  
                            case 2:  
                                Value = Data.ProductsOrServicesDescription;  
                                break;  
                            case 3:  
                                Value = Data.Quantity;  
                                break;  
                            case 4:  
                                Value = Data.UnitOfMeasurement;  
                                break;  
                            case 5:  
                                Value = Data.UnitPrice;  
                                break;  
                            case 6:  
                                Value = Data.Discount;  
                                break;  
                            case 7:  
                                Value = Data.TaxDutyVat;  
                                break;  
                            case 8:  
                                Value = Data.GuaranteeOrWarrantyPeriod;  
                                break;  
                            case 9:  
                                Value = Data.TotalAmount;  
                                break;  
                        }  
                        PDF_Table.AddCell(new Phrase(Value, DT_Font));  
                    }  
                }  
    

    Output:
    169661-output.gif
    Thank you very much Peter

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.