C# создание и печать файла

119
30 декабря 2020, 08:10

На работе постоянно приходится печатать маленькие этикетки для груза. На данный момент заполняется excel таблица и печатается нужное количество из нее. (примерно такого формата)

Нужно много что заполнить, выделить нужное количество... В общем долго...

Появилась идея сделать небольшую софтину, где нужно заполнить форму и указать количество этих этикеток, софтина бы сама распределила их на странице и отправила в печать.

Как ой подход к данной задаче вы можете предложить?

Мои варианты:

  • Создать excel файл заполнить его, и напечатать. (если это вообще возможно)

  • Создать многостраничный документ xps/pdf/word... И печатать его.

  • Создать набор картинок и печатать их. (наверное самый трудный вариант)

Answer 1

На мой взгляд, проще всего сверстать вашу картинку в WPF-приложении.

Если ваша картинка находится, например, в Grid'е с именем main, то вы можете её напечатать при помощи

var dialog = new PrintDialog();
if (dialog.ShowDialog() == true) // возвращает bool?, поэтому сравнение с true
{
    dialog.PrintVisual(main, "Вывод этикетки на печать");
}

Ещё документация:

  • How to: Invoke a Print Dialog

Дополнение: для вёрстки проще всего использовать MVVM. Для вот такого класса:

public class Label
{
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string InvoiceNo { get; set; }
    public string OrderNo { get; set; }
    public string ItemNo { get; set; }
}

и XAML'а

<ItemsControl Width="600" Height="800" ItemsSource="{Binding}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border Width="150" BorderBrush="Black" BorderThickness="3" Margin="0,0,-3,-3">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <TextBlock FontSize="14" Text="{Binding Address1}" Grid.Row="0" Grid.ColumnSpan="2" HorizontalAlignment="Center"/>
                    <TextBlock FontSize="12" Text="{Binding Address2}" Grid.Row="1" Grid.ColumnSpan="2" HorizontalAlignment="Center"/>
                    <TextBlock FontSize="13" FontStyle="Italic" Text="Накладная:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Center"/>
                    <TextBlock FontSize="13" Text="{Binding InvoiceNo}" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center"/>
                    <TextBlock FontSize="13" FontStyle="Italic" Text="Заказ:" Grid.Row="3" Grid.Column="0" HorizontalAlignment="Center"/>
                    <TextBlock FontSize="13" Text="{Binding OrderNo}" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Center"/>
                    <TextBlock FontSize="13" FontStyle="Italic" Text="Место:" Grid.Row="4" Grid.Column="0" HorizontalAlignment="Center"/>
                    <TextBlock FontSize="13" FontWeight="Bold" Text="{Binding ItemNo}" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Center"/>
                </Grid>
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

и DataContext

new[]
{
    new Label()
    {
        Address1 = "Куда-то там",
        Address2 = "Адрес 4",
        InvoiceNo = "2222222222",
        OrderNo = "1111111111",
        ItemNo = "1"
    },
    new Label()
    {
        Address1 = "Куда-то там",
        Address2 = "Адрес 4",
        InvoiceNo = "2222222222",
        OrderNo = "1111111111",
        ItemNo = "2"
    }
}

получается следующая картинка:

(Понятно, DataContext лучше генерировать в цикле.)

Если надо вывести несколько страниц, можно просто вызвать PrintVisual в цикле несколько раз. Однако это создаст несколько заданий на печать. Чтобы оформить это всё как одно задание, нужно предоставить DocumentPaginator и вызвать dialog.PrintDocument вместо PrintVisual. Набросал простейшую имплементацию:

public class Paginator : Document​Paginator
{
    Visual[] pages;
    public Paginator(params Visual[] pages)
    {
        this.pages = pages;
        this.Source = new S() { DocumentPaginator = this };
    }
    public override bool IsPageCountValid => true;
    public override int PageCount => pages.Length;
    public override Size PageSize { get; set; }
    class S : IDocumentPaginatorSource
    {
        public DocumentPaginator DocumentPaginator { get; set; }
    }
    public override IDocumentPaginatorSource Source { get; }
    public override DocumentPage GetPage(int pageNumber) =>
        new DocumentPage(pages[pageNumber]);
}

Печатать так:

var dialog = new PrintDialog();
if (dialog.ShowDialog() == true) // возвращает bool?, поэтому сравнение с true
{
    dialog.PrintDocument(new Paginator(grid1, grid2, grid3), "Вывод этикетки на печать");
}
Answer 2

Вообще, из предложенных вам пунктов, последний наверное самый простой. Просто рисуете через GDI и все. Вот тут - https://msdn.microsoft.com/en-us/library/bb383872(v=vs.90).aspx можно почитать.

Другой момент, можно работать с excel через Interop (ole) - https://stackoverflow.com/questions/854693/printing-excel-using-interop . Так же можно и взаимодействовать с книгой и страницами. Но, это требует обязательно установленного Excel-я.

По поводу Pdf - как по мне, реализация отрисовки изображений сопоставима по объему кода с реализацией логики отрисовки PDF. Поэтому, тут уже кому как удобнее.

READ ALSO
Почему я не могу задать минимальную высоту в GUI.BOX

Почему я не могу задать минимальную высоту в GUI.BOX

Я хочу сделать полоску над врагом, получается вот это:

130
как снизить нагрузку при рисовании на Canvas wpf

как снизить нагрузку при рисовании на Canvas wpf

При рисовании на canvas'е загружает ЦП до 60%

101
Заменить символы в TextBox для ввода пароля C# WPF MVVM

Заменить символы в TextBox для ввода пароля C# WPF MVVM

Так исторически сложилось, что необходимо использовать TextBox для ввода логина и пароляКак правильно организовать замену символов в текстовом...

135