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

420
16 августа 2017, 15:48

На работе постоянно приходится печатать маленькие этикетки для груза. На данный момент заполняется 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
Вывод DateTime в DataGrid

Вывод DateTime в DataGrid

Имеется класс MyTable, состоящий из нескольких свойств,включая DateTime date Также имеется массив MyTable[] data; В него я подгружаю данные из файла:

453
Как выделить предыдущую строку в DataGridView?

Как выделить предыдущую строку в DataGridView?

Есть гридПри нажатии на строку в гриде, отображается в текстбоксах доп

248
Как обратиться из внедренного скрипта в страницу (с помощью одного из файлов content_scripts) к непосредственно файлу из списка content_scripts?

Как обратиться из внедренного скрипта в страницу (с помощью одного из файлов content_scripts) к непосредственно файлу из списка content_scripts?

Знаю, что можно общаться между фоновым скриптом и скриптом из content_scripts с помощью рантайма, но можно ли общаться между внедренным скриптом...

186
Якорь на React js

Якорь на React js

Всем привет, Делаю свое первое приложение на Reactjs и побольшей части это просто компонентная верстка

1303