WPF mvvm datagrid export as pdf via iTextSharp

Install-Package iTextSharp;

 

public ICommand ExportAsPDFCommand { get; private set; }


ExportAsPDFCommand = new DelCommand(async (obj) => await ExportAsPDFCommandExecuted(obj));


private async Task ExportAsPDFCommandExecuted(object? obj)
{
    try
    {
        exportedIdx = 0;
        var dg = obj as DataGrid;
        var items = dg.Items.Cast<Book>()?.ToList();
        batchCount = items.Count() % batchSize > 0 ? items.Count() / batchSize + 1 : items.Count() / batchSize;
        SaveFileDialog dialog = new SaveFileDialog();
        dialog.Filter = $"PDF Files|*.pdf";
        dialog.FileName = $"PDF_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}_{Guid.NewGuid():N}";
        if (dialog.ShowDialog() == true)
        {
            await Task.Run(async () =>
            {
                await ExportListDataInPDFAsync(items, dialog.FileName);
                await Application.Current.Dispatcher.InvokeAsync(() =>
                {
                    MessageBox.Show($"Exported file in {dialog.FileName}!");
                });
            });
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);                 
    }
}

private async Task ExportListDataInPDFAsync<T>(List<T> dataList, string pdfFileName)
{            
    await Task.Run(async() =>
    {
        exportedIdx = 0;
        await PopulateStatusMsg($"Start exporting in pdf");
        //Create document and writer
        using (var pdfDoc = new Document())
        {
            using (var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream(pdfFileName, FileMode.Create)))
            {
                pdfDoc.Open();

                // Add title
                var titleFont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 18);
                var titleParagraph = new Paragraph($"Data Export - {typeof(T).Name}", titleFont)
                {
                    Alignment = Element.ALIGN_CENTER,
                    SpacingAfter = 20f
                };
                pdfDoc.Add(titleParagraph);

                // Add export date
                var dateFont = FontFactory.GetFont(FontFactory.HELVETICA, 10);
                var dateParagraph = new Paragraph($"Exported on: {DateTime.Now:yyyy-MM-dd HH:mm:ss}", dateFont)
                {
                    Alignment = Element.ALIGN_RIGHT,
                    SpacingAfter = 15f
                };
                pdfDoc.Add(dateParagraph);

                if (dataList == null || !dataList.Any())
                {
                    // Handle empty list
                    var emptyFont = FontFactory.GetFont(FontFactory.HELVETICA_OBLIQUE, 12);
                    var emptyParagraph = new Paragraph("No data available to export.", emptyFont)
                    {
                        Alignment = Element.ALIGN_CENTER,
                        SpacingAfter = 20f
                    };
                    pdfDoc.Add(emptyParagraph);
                }
                else
                {
                    // Create table with columns based on object properties
                    var props = typeof(T).GetProperties();
                    var table = new PdfPTable(props.Length)
                    {
                        WidthPercentage = 100,
                        SpacingBefore = 10f,
                        SpacingAfter = 10f
                    };

                    // Set column widths (optional - adjust as needed)
                    float[] columnWidths = new float[props.Length];
                    for (int i = 0; i < props.Length; i++)
                    {
                        columnWidths[i] = 1f;
                    }
                    table.SetWidths(columnWidths);

                    // Add header row
                    var headerFont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 10);
                    foreach (var prop in props)
                    {
                        var cell = new PdfPCell(new Phrase(prop.Name, headerFont))
                        {
                            BackgroundColor = new BaseColor(220, 220, 220),
                            HorizontalAlignment = Element.ALIGN_CENTER,
                            Padding = 5f
                        };
                        table.AddCell(cell);
                    }

                    // Add data rows
                    var dataFont = FontFactory.GetFont(FontFactory.HELVETICA, 9);
                    foreach (var item in dataList)
                    {
                        foreach (var property in props)
                        {
                            var value = property.GetValue(item)?.ToString() ?? string.Empty;
                            var cell = new PdfPCell(new Phrase(value, dataFont))
                            {
                                Padding = 4f,
                                HorizontalAlignment =(int) HorizontalAlignment.Center
                            };
                            table.AddCell(cell);
                        }

                        if(++exportedIdx%100000==0)
                        {
                            await PopulateStatusMsg($"Exported {exportedIdx} items in pdf");
                        }
                    }

                    await PopulateStatusMsg($"Adding table...");
                    pdfDoc.Add(table);

                    // Add summary
                    var summaryFont = FontFactory.GetFont(FontFactory.HELVETICA, 10);
                    var summaryParagraph = new Paragraph($"Total records: {dataList.Count}", summaryFont)
                    {
                        Alignment = Element.ALIGN_RIGHT,
                        SpacingBefore = 10f
                    };
                    
                    pdfDoc.Add(summaryParagraph);
                }
                pdfDoc.Close();
                await PopulateStatusMsg($"Expoted in {pdfFileName} pdf file successfully");
            }
        }
    });
}

 

 

 

image

 

 

 

 

 

image

 

 

 

image

 

 

 

image

 

 

 

//App.xaml
<Application x:Class="WpfApp31.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApp31">
    <Application.Resources>
         
    </Application.Resources>
</Application>


//App.xaml.cs
using Microsoft.Extensions.DependencyInjection;
using System.Configuration;
using System.Data;
using System.Windows;

namespace WpfApp31
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        IServiceProvider serviceProvider;
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            var services = new ServiceCollection();
            ConfigureServices(services);
            serviceProvider = services.BuildServiceProvider();

            var mainWin=serviceProvider.GetRequiredService<MainWindow>();
            mainWin?.Show();
        }

        private void ConfigureServices(ServiceCollection services)
        {
            services.AddSingleton<IIDService, IDService>();
            services.AddSingleton<INameService, NameService>();
            services.AddSingleton<IISBNService, ISBNService>();
            services.AddSingleton<MainWindow>();
            services.AddSingleton<MainVM>();
        }
    }

}


//MainWindow.xaml
<Window x:Class="WpfApp31.MainWindow"
        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:local="clr-namespace:WpfApp31"
        WindowState="Maximized"
        mc:Ignorable="d"
        Title="{Binding MainTitle}" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <DataGrid Grid.Row="0"
                  ItemsSource="{Binding BooksCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                  VirtualizingPanel.IsVirtualizing="True"
                  VirtualizingPanel.VirtualizationMode="Recycling"
                  VirtualizingPanel.CacheLength="2,2"
                  VirtualizingPanel.CacheLengthUnit="Item"
                  ScrollViewer.IsDeferredScrollingEnabled="True"
                  ScrollViewer.CanContentScroll="True"
                  AutoGenerateColumns="False"
                  CanUserAddRows="False">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Grid Width="{Binding DataContext.GridWidth,RelativeSource={RelativeSource AncestorType=Window}}"
                                  Height="{Binding DataContext.GridHeight,RelativeSource={RelativeSource AncestorType=Window}}">
                                <Grid.Background>
                                    <ImageBrush ImageSource="{Binding ImgSource}" Stretch="Uniform"/>
                                </Grid.Background>
                                <Grid.RowDefinitions>
                                    <RowDefinition/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition/>
                                    <ColumnDefinition/>
                                    <ColumnDefinition/>
                                    <ColumnDefinition/>
                                </Grid.ColumnDefinitions>
                                <Grid.Resources>
                                    <Style TargetType="TextBlock">
                                        <Setter Property="FontSize" Value="30"/>
                                        <Style.Triggers>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="FontSize" Value="50"/>
                                                <Setter Property="Foreground" Value="Red"/>
                                            </Trigger>
                                        </Style.Triggers>
                                    </Style>
                                </Grid.Resources>
                                <TextBlock Text="{Binding Id}" Grid.Row="0" Grid.Column="0"/>
                                <TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="1"/>
                                <TextBlock Text="{Binding Title}" Grid.Row="0" Grid.Column="2"/>
                                <TextBlock Text="{Binding Topic}" Grid.Row="0" Grid.Column="3"/>
                                <TextBlock Text="{Binding ISBN}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4"
                                           HorizontalAlignment="Center"/>
                            </Grid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
            <DataGrid.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Export As Excel"
                              Command="{Binding ExportAsExcelCommand}"
                              CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu},Path=PlacementTarget}"/>
                    <MenuItem Header="Export As PDF"
                              Command="{Binding ExportAsPDFCommand}"
                              CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu},Path=PlacementTarget}"/>
                </ContextMenu>
            </DataGrid.ContextMenu>
        </DataGrid>

        <TextBlock Grid.Row="1"
                   Text="{Binding StatusMsg}"
                   FontSize="30"/>
    </Grid>
</Window>


//MainWindow.xaml.cs
using CommunityToolkit.Mvvm.ComponentModel;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Microsoft.Win32;
using OfficeOpenXml;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Document = iTextSharp.text.Document;
using Paragraph = iTextSharp.text.Paragraph;

namespace WpfApp31
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow(MainVM vm)
        {
            InitializeComponent();
            this.DataContext = vm;
            this.Loaded += async (s, e) =>
            {
                vm.GridWidth = this.ActualWidth;
                vm.GridHeight = this.ActualHeight / 2;
                await vm.InitPopulateAsync();
            };
        }
    }

    public partial class MainVM : ObservableObject
    {
        IIDService idService;
        INameService nameService;
        IISBNService isbnService;
        List<string> imgsList;
        int imgsCount = 0;
        int imgsIdx = 0;
        int batchSize = 1_000_000;
        int batchCount = 0;
        int exportedIdx = 0;
        private ConcurrentDictionary<string, ImageSource> imgDicCache = new ConcurrentDictionary<string, ImageSource>();
        public ICommand ExportAsExcelCommand { get; private set; }
        public ICommand ExportAsPDFCommand { get; private set; }
        public MainVM(IIDService idServiceValue, INameService nameServiceValue, IISBNService isbnServiceValue)
        {
            idService = idServiceValue;
            nameService = nameServiceValue;
            isbnService = isbnServiceValue;
            MainTitle = $"Now is {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}";
            ExportAsExcelCommand = new DelCommand(async (obj) => await ExportAsExcelCommandExecuted(obj));
            ExportAsPDFCommand = new DelCommand(async (obj) => await ExportAsPDFCommandExecuted(obj));
            InitImgsList();
            Task.Run(() =>
            {
                InitTimer();
            });
        }

        private async Task ExportAsPDFCommandExecuted(object? obj)
        {
            try
            {
                exportedIdx = 0;
                var dg = obj as DataGrid;
                var items = dg.Items.Cast<Book>()?.ToList();
                batchCount = items.Count() % batchSize > 0 ? items.Count() / batchSize + 1 : items.Count() / batchSize;
                SaveFileDialog dialog = new SaveFileDialog();
                dialog.Filter = $"PDF Files|*.pdf";
                dialog.FileName = $"PDF_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}_{Guid.NewGuid():N}";
                if (dialog.ShowDialog() == true)
                {
                    await Task.Run(async () =>
                    {
                        await ExportListDataInPDFAsync(items, dialog.FileName);
                        await Application.Current.Dispatcher.InvokeAsync(() =>
                        {
                            MessageBox.Show($"Exported file in {dialog.FileName}!");
                        });
                    });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);                 
            }
        }

        private async Task ExportListDataInPDFAsync<T>(List<T> dataList, string pdfFileName)
        {            
            await Task.Run(async() =>
            {
                exportedIdx = 0;
                await PopulateStatusMsg($"Start exporting in pdf");
                //Create document and writer
                using (var pdfDoc = new Document())
                {
                    using (var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream(pdfFileName, FileMode.Create)))
                    {
                        pdfDoc.Open();

                        // Add title
                        var titleFont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 18);
                        var titleParagraph = new Paragraph($"Data Export - {typeof(T).Name}", titleFont)
                        {
                            Alignment = Element.ALIGN_CENTER,
                            SpacingAfter = 20f
                        };
                        pdfDoc.Add(titleParagraph);

                        // Add export date
                        var dateFont = FontFactory.GetFont(FontFactory.HELVETICA, 10);
                        var dateParagraph = new Paragraph($"Exported on: {DateTime.Now:yyyy-MM-dd HH:mm:ss}", dateFont)
                        {
                            Alignment = Element.ALIGN_RIGHT,
                            SpacingAfter = 15f
                        };
                        pdfDoc.Add(dateParagraph);

                        if (dataList == null || !dataList.Any())
                        {
                            // Handle empty list
                            var emptyFont = FontFactory.GetFont(FontFactory.HELVETICA_OBLIQUE, 12);
                            var emptyParagraph = new Paragraph("No data available to export.", emptyFont)
                            {
                                Alignment = Element.ALIGN_CENTER,
                                SpacingAfter = 20f
                            };
                            pdfDoc.Add(emptyParagraph);
                        }
                        else
                        {
                            // Create table with columns based on object properties
                            var props = typeof(T).GetProperties();
                            var table = new PdfPTable(props.Length)
                            {
                                WidthPercentage = 100,
                                SpacingBefore = 10f,
                                SpacingAfter = 10f
                            };

                            // Set column widths (optional - adjust as needed)
                            float[] columnWidths = new float[props.Length];
                            for (int i = 0; i < props.Length; i++)
                            {
                                columnWidths[i] = 1f;
                            }
                            table.SetWidths(columnWidths);

                            // Add header row
                            var headerFont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 10);
                            foreach (var prop in props)
                            {
                                var cell = new PdfPCell(new Phrase(prop.Name, headerFont))
                                {
                                    BackgroundColor = new BaseColor(220, 220, 220),
                                    HorizontalAlignment = Element.ALIGN_CENTER,
                                    Padding = 5f
                                };
                                table.AddCell(cell);
                            }

                            // Add data rows
                            var dataFont = FontFactory.GetFont(FontFactory.HELVETICA, 9);
                            foreach (var item in dataList)
                            {
                                foreach (var property in props)
                                {
                                    var value = property.GetValue(item)?.ToString() ?? string.Empty;
                                    var cell = new PdfPCell(new Phrase(value, dataFont))
                                    {
                                        Padding = 4f,
                                        HorizontalAlignment =(int) HorizontalAlignment.Center
                                    };
                                    table.AddCell(cell);
                                }

                                if(++exportedIdx%100000==0)
                                {
                                    await PopulateStatusMsg($"Exported {exportedIdx} items in pdf");
                                }
                            }

                            await PopulateStatusMsg($"Adding table...");
                            pdfDoc.Add(table);

                            // Add summary
                            var summaryFont = FontFactory.GetFont(FontFactory.HELVETICA, 10);
                            var summaryParagraph = new Paragraph($"Total records: {dataList.Count}", summaryFont)
                            {
                                Alignment = Element.ALIGN_RIGHT,
                                SpacingBefore = 10f
                            };
                            
                            pdfDoc.Add(summaryParagraph);
                        }
                        pdfDoc.Close();
                        await PopulateStatusMsg($"Expoted in {pdfFileName} pdf file successfully");
                    }
                }
            });
        }

        private async Task ExportAsExcelCommandExecuted(object? obj)
        {
            try
            {
                await PopulateStatusMsg($"Start exporting");
                exportedIdx = 0;
                var dg = obj as DataGrid;
                var items = dg.Items.Cast<Book>()?.ToList();
                batchCount = items.Count() % batchSize > 0 ? items.Count() / batchSize + 1 : items.Count() / batchSize;
                SaveFileDialog dialog = new SaveFileDialog();
                dialog.Filter = $"Excel Files|*.xlsx";
                dialog.FileName = $"Excel_{DateTime.Now.ToString("yyyyMMddHHmmssffff")}_{Guid.NewGuid():N}";
                if (dialog.ShowDialog() == true)
                {
                    await Task.Run(async () =>
                    {
                        await ExportListDataInExcelAsync(items, dialog.FileName);
                        await Application.Current.Dispatcher.InvokeAsync(() =>
                        {
                            MessageBox.Show($"Exported file in {dialog.FileName}!");
                        });
                    });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);                 
            }           
        }

        private async Task ExportListDataInExcelAsync<T>(List<T> dataList, string excelFileName)
        {
            EPPlusLicense license = new EPPlusLicense();
            license.SetNonCommercialPersonal("Fred");

            using (ExcelPackage package = new ExcelPackage())
            {
                var props = typeof(T).GetProperties();
                for (int i = 0; i < batchCount; i++)
                {
                    var tempBooksList = dataList.Skip(i * batchSize).Take(batchSize).ToList();
                    var workSheet = package.Workbook.Worksheets.Add($"Sheet_{i + 1}");
                    for (int j = 0; j < props.Count(); j++)
                    {
                        workSheet.Cells[1, j + 1].Value = props[j].Name;
                    }

                    for (int row = 0; row < tempBooksList.Count; row++)
                    {
                        ++exportedIdx;
                        for (int col = 0; col < props.Length; col++)
                        {
                            var value = props[col].GetValue(tempBooksList[row]);
                            workSheet.Cells[row + 2, col + 1].Value = value;
                        }
                    }
                    // Format headers
                    using (var range = workSheet.Cells[1, 1, 1, props.Length])
                    {
                        range.Style.Font.Bold = true;
                        range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
                        range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightBlue);
                    }

                    // Auto-fit columns
                    workSheet.Cells[workSheet.Dimension.Address].AutoFitColumns();
                    await PopulateStatusMsg($"Exported {exportedIdx} items");
                }
                await PopulateStatusMsg($"Writing in {excelFileName} items");
                package.SaveAs(new FileInfo(excelFileName));
            }
            await PopulateStatusMsg($"Exported in {excelFileName} successfully!");
        }

        private async Task PopulateStatusMsg(string msgValue)
        {
            await Application.Current.Dispatcher.InvokeAsync(() =>
            {
                StatusMsg = msgValue;
            });
        }

        private void InitImgsList()
        {
            var imgDir = @"../../../Images";
            if (!Directory.Exists(imgDir))
            {
                return;
            }

            imgsList = new List<string>(Directory.GetFiles(imgDir));
            imgsCount = imgsList.Count;
        }

        public async Task InitPopulateAsync()
        {
            BooksCollection = new ObservableCollection<Book>();
            List<Book> booksList = new List<Book>();
            for (int i = 1; i < 1000101; i++)
            {
                booksList.Add(new Book()
                {
                    Id = idService.GetID(),
                    Name = nameService.GetName(),
                    ISBN = isbnService.GetISBN(),
                    Title = $"Title_{i}",
                    Topic = $"Topic_{i}",
                    ImgSource = GetImgSourceViaUrl(imgsList[imgsIdx % imgsCount])
                });
                ++imgsIdx;

                if (i % 100000 == 0)
                {
                    await PopulateBooksCollectionAsync(booksList);
                }
            }

            if (booksList.Any())
            {
                await PopulateBooksCollectionAsync(booksList);
            }

            StatusMsg = $"Loaded completely,now is {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}," +
                $"loaded {BooksCollection.Count} items,memory:{GetMemory()}";
        }

        private ImageSource GetImgSourceViaUrl(string imgUrl)
        {
            if (!File.Exists(imgUrl))
            {
                return null;
            }

            if (imgDicCache.TryGetValue(imgUrl, out var img))
            {
                return img;
            }

            BitmapImage bmi = new BitmapImage();
            bmi.BeginInit();
            bmi.UriSource = new Uri(imgUrl, UriKind.RelativeOrAbsolute);
            bmi.EndInit();
            bmi.CacheOption = BitmapCacheOption.OnDemand;
            if (bmi.CanFreeze)
            {
                bmi.Freeze();
            }
            imgDicCache[imgUrl] = bmi;
            return bmi;
        }

        private async Task PopulateBooksCollectionAsync(List<Book> booksList)
        {
            var tempBooks = booksList.ToList();
            booksList.Clear();
            await Application.Current.Dispatcher.InvokeAsync(() =>
            {
                foreach (var bk in tempBooks)
                {
                    BooksCollection.Add(bk);
                }
                StatusMsg = $"Now is {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}," +
                $"loaded {BooksCollection.Count} items,memory:{GetMemory()}";
            }, System.Windows.Threading.DispatcherPriority.Background);
        }

        private string GetMemory()
        {
            var memory = Process.GetCurrentProcess().PrivateMemorySize64;
            return $"{(memory / 1024 / 1024).ToString("#,##0.00")} M";
        }

        private void InitTimer()
        {
            System.Timers.Timer tmr = new System.Timers.Timer();
            tmr.Interval = 1000;
            tmr.Elapsed += Tmr_Elapsed;
            tmr.Start();
        }

        private void Tmr_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            MainTitle = $"Now is {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}";
        }


        [ObservableProperty]
        private ObservableCollection<Book> booksCollection;

        [ObservableProperty]
        private string mainTitle;

        [ObservableProperty]
        private double gridWidth;

        [ObservableProperty]
        private double gridHeight;

        [ObservableProperty]
        private string statusMsg;
    }

    public class DelCommand : ICommand
    {
        private Action<object?> execute;
        private Predicate<object?> canExecute;
        public DelCommand(Action<object?> executeValue, Predicate<object?> canExecuteValue = null)
        {
            execute = executeValue;
            canExecute = canExecuteValue;
        }

        public event EventHandler? CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        public bool CanExecute(object? parameter)
        {
            return canExecute == null ? true : canExecute(parameter);
        }

        public void Execute(object? parameter)
        {
            execute(parameter);
        }
    }

    public class Book
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string ISBN { get; set; }
        public string Title { get; set; }
        public string Topic { get; set; }
        public ImageSource ImgSource { get; set; }
    }

    public interface IIDService
    {
        int GetID();
    }

    public class IDService : IIDService
    {
        int idx = 0;

        public int GetID()
        {
            return Interlocked.Increment(ref idx);
        }
    }


    public interface INameService
    {
        string GetName();
    }

    public class NameService : INameService
    {
        int idx = 0;

        public string GetName()
        {
            return $"Name_{++idx}";
        }
    }

    public interface IISBNService
    {
        string GetISBN();
    }

    public class ISBNService : IISBNService
    {
        int idx = 0;

        public string GetISBN()
        {
            return $"ISBN_{++idx}_{Guid.NewGuid():N}";
        }
    }
}

 

posted @ 2025-10-09 21:32  FredGrit  阅读(4)  评论(0)    收藏  举报