Laden...

WPF: Drucker druckt weiße Seiten

Erstellt von dr0n3 vor 10 Jahren Letzter Beitrag vor 10 Jahren 2.713 Views
D
dr0n3 Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren
WPF: Drucker druckt weiße Seiten

Einen wunderschönen guten Abend zusammen,

ich versuche nun seit geraumer Zeit, mein Programm dazu zu bringen, eine Liste mit diversen Daten zu drucken.

Ich fasse das Problem mal als kurzen Abriss zusammen:

Ich selbst habe einen Brother HL-2250DN. Der druckt die Liste, genau wie der XPS Drucker, wunderbar. Bei Freunden oder dem Auftraggeber (HP und Kyocera) werden jedoch nur weiße Seiten gedruckt. Zunächst habe ich mich dann im Grunde nach dem Artikel How to Print in WPF to Fit to printing page gerichtet (skalieren der Seite aufs Papier).

Das Problem hierbei ist jedoch, dass mir eine Exception ausgegeben wird, welche meint, dass "Desired-Size" kein NaN-Wert sein dürfe. Ein Blick auf die Werte der Variablen (s. Code) hat dann ergeben, dass "clp.ActualHeight" bzw "-Width" tatsächlich "0" sind und "scale" damit "Infinity".
Durch das rumprobieren bin ich mittlerweile an dem Punkt angekommen, bei dem ich "clp.ActualHeight/Width" mit "clp.Height/Width" ersetzt habe.

Nun ist das ganze jedoch noch verwirrender, denn jetzt wird die Seite zwar gedruckt, jedoch fehlen jegliche Daten (welche per Property gesetzt werden).

Ich bin nun im Grunde zutiefst verwirrt und frage deshalb hier um Hilfe.

mfG,
dr0n3

Funktion zum Drucken


ClassViewModel vm = (ClassViewModel)dataGrid.SelectedItem;
PrintDialog printDlg = new PrintDialog();


if (printDlg.ShowDialog() != true)
{ return; }

ListPrint clp = new ListPrint();
clp.Heading = "Kursliste - " + vm.Label + " (" + vm.Subject.Subject + ")";
clp.Teacher = vm.Teacher;
clp.Time = vm.Time;
clp.Room = vm.Room;
clp.Rail = vm.Rail;

for (int i = 0; i < vm.Students.Count; i++)
{
    StudentViewModel viewmodel = vm.Students[i];
    clp.AddStudent(viewmodel);
}

// Mein Brother druckt problemlos ohne den Code von hier...

System.Printing.PrintCapabilities capabilities = 
    PrintDlg.PrintQueue.GetPrintCapabilities(printDlg.PrintTicket);

// Debug-Werte, die ich ausgelesen habe
double d = capabilities.PageImageableArea.ExtentWidth; // = 761.60125984251965  
double p = capabilities.PageImageableArea.ExtentHeight; // = 1690.2425196850393
double d1 = clp.ActualWidth; // = 0
double p1 = clp.ActualHeight; // = 0

double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / clp.ActualWidth, 
    capabilities.PageImageableArea.ExtentHeight / clp.ActualHeight); // = Infinity

clp.LayoutTransform = new ScaleTransform(scale, scale);
Size sz = new Size(capabilities.PageImageableArea.ExtentWidth, 
    capabilities.PageImageableArea.ExtentHeight);

clp.Measure(sz); // Exception
clp.Arrange(new Rect(new Point(capabilities.PageImageableArea.OriginWidth, 
    capabilities.PageImageableArea.OriginHeight), sz));

// ...bis hier

printDlg.PrintVisual(clp, "Kursliste");

ListPrint.xaml (Muster für den Druck)


<UserControl x:Class="CheckIn.ListPrint"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="990" d:DesignWidth="700"
         Width="700" Height="990">
<Grid x:Name="mainGrid">
    // Label, Grafiken usw.
</Grid>
</UserControl>

849 Beiträge seit 2006
vor 10 Jahren

Hi, hab nur mal schnell gegoogelt:

hilft Dir das weiter?: Why are ActualWidth and ActualHeight 0.0 in this case?

ich vermute das eigentliche Problem ist, das das Control nie angezeigt wird und Du deshalb einiges selbst machen musst.

D
dr0n3 Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren

Danke zuerst einmal für die Antwort.

Ich habe daraufhin

clp.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            clp.Arrange(new Rect(new Point(0,0), clp.DesiredSize));

in die vorletzte Zeile eingefügt.

Nun bin ich zumindest einen kleinen Schritt weiter, denn das Blatt ist nichtmehr weiß, sondern der Inhalt wird richtig skaliert und gedruckt.

Das Problem ist jetzt nur, dass die Seiten (wie oben auch schon einmal geschrieben) die per Property gesetzten Daten nicht beinhalten.

Es werden also Labels, DataGrids etc gedruckt, alles, was jedoch in diesem Teil


clp.Heading = "Kursliste - " + vm.Label + " (" + vm.Subject.Subject + ")";
clp.Teacher = vm.Teacher;
clp.Time = vm.Time;
clp.Room = vm.Room;
clp.Rail = vm.Rail;

for (int i = 0; i < vm.Students.Count; i++)
{
    StudentViewModel viewmodel = vm.Students[i];
    clp.AddStudent(viewmodel);
}

geschiet bleibt aus. Zum besseren Verständnis einfach mal das Control, dass gedruckt wird und die Ausgabe.

ListPrint.xaml


<UserControl x:Class="CheckIn.ListPrint"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="990" d:DesignWidth="700"
             Height="990"
             Width="700">
    <Grid x:Name="mainGrid">
        <Label Content="{Binding Heading}" FontSize="32" HorizontalAlignment="Center" Margin="0,10,0,0" VerticalAlignment="Top"/>
        <Label Content="{Binding Date}" HorizontalAlignment="Right" Margin="0,10,40,0" VerticalAlignment="Top"/>
        <Image HorizontalAlignment="Left" Height="164" Margin="10,10,0,0" VerticalAlignment="Top" Width="153" Source="../Images/logo.jpg" RenderTransformOrigin="0.5,0.5"/>
        <Grid HorizontalAlignment="Center" Height="106" Margin="181,68,181,0" VerticalAlignment="Top" Width="338">
            <Label Content="Lehrer:" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="55"/>
            <Label Content="Zeit:" HorizontalAlignment="Left" Margin="0,26,0,0" VerticalAlignment="Top" Width="55"/>
            <Label Content="Raum:" HorizontalAlignment="Left" Margin="0,52,0,0" VerticalAlignment="Top" Width="55"/>
            <Label Content="{Binding Teacher}" HorizontalAlignment="Left" Margin="60,0,0,0" VerticalAlignment="Top"/>
            <Label Content="{Binding Time}" HorizontalAlignment="Left" Margin="60,26,0,0" VerticalAlignment="Top" Width="52"/>
            <Label Content="{Binding Room}" HorizontalAlignment="Left" Margin="60,52,0,0" VerticalAlignment="Top"/>
            <Label Content="Schiene:" HorizontalAlignment="Left" Margin="0,78,0,0" VerticalAlignment="Top" Width="55"/>
            <Label Content="{Binding Rail}" HorizontalAlignment="Left" Margin="60,78,0,0" VerticalAlignment="Top"/>
            <Label Content="männlich:" Margin="0,0,46,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="61"/>
            <Label Content="{Binding Male}" HorizontalAlignment="Right" Margin="0,0,25,0" VerticalAlignment="Top"/>
            <Label Content="weiblich:" Margin="0,26,46,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="61"/>
            <Label Content="{Binding Female}" HorizontalAlignment="Right" Margin="0,26,25,0" VerticalAlignment="Top"/>
            <Label Content="gesamt:" Margin="0,52,46,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="61"/>
            <Label Content="{Binding Quantity}" HorizontalAlignment="Right" Margin="0,52,25,0" VerticalAlignment="Top"/>
        </Grid>
        <DataGrid x:Name="dataGrid" Margin="40,200,60,0" VerticalAlignment="Top"
                  AutoGenerateColumns="False" CanUserAddRows="False" IsReadOnly="True" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Nummer" Binding="{Binding Number}" MinWidth="60"/>
                <DataGridTextColumn Header="Name" Binding="{Binding LastName}" MinWidth="150"/>
                <DataGridTextColumn Header="Vorname" Binding="{Binding FirstName}" MinWidth="100"/>
                <DataGridTextColumn Header="M/W" Binding="{Binding Gender}" MinWidth="35"/>
                <DataGridTextColumn Header="Klasse" Binding="{Binding SchoolClass}" MinWidth="50"/>
            </DataGrid.Columns>
        </DataGrid>
        <Label Content="CheckIn von mir, 2013" HorizontalAlignment="Center" Margin="0,0,0,10" VerticalAlignment="Bottom"/>
    </Grid>
</UserControl>

Resultat: <siehe Anhang>
(hier sei erwähnt, dass es im XPS Drucker nach wie vor funktioniert. Das Bild ist ein Screenshot aus selbigem, welches ich nachbearbeitet hab)

849 Beiträge seit 2006
vor 10 Jahren

Kann das sein das dein Drucker in irgendeiner Form eine Vorschau bringt, die das ganze dann schon richtig initialisiert? Also wenns auf einem anderen Drucker nicht schon funktioniert würde ich fragen ob INotifyPropertyChanged implementiert ist.

D
dr0n3 Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren

Eine Druckvorschau wird mir persönlich nicht angezeigt und mit dem zusätzlichen Code oben druckt er auf allen druckern das gleiche.
Also:

ohne Measure und Arrange: mein Brother druckt richtig, die anderen weiß
mit Measure und Arrange: alle Drucken ohne den Inhalt

Die Properties an sich funktionieren im Übrigen auch, da

MessageBox.Show(clp.Heading + " " + clp.Teacher);

mir die richtigen Werte ausgibt.
Außerdem dürfte mein Drucker ja dann eben ohne Measure/Arrange nicht fehlerfrei drucken, richtig?

mfG,
dr0n3


public partial class ListPrint : UserControl,INotifyPropertyChanged
    {
        // konstruktor

        private string heading = "";
        public string Heading
        {
            get
            {
                return heading;
            }
            set
            {
                if (value != heading)
                {
                    heading = value;
                    NotifyPropertyChanged("Heading");
                }
            }
        }

// weitere properties

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
}

849 Beiträge seit 2006
vor 10 Jahren

Die Properties an sich funktionieren im Übrigen auch, da

MessageBox.Show(clp.Heading + " " + clp.Teacher);  

mir die richtigen Werte ausgibt.
Außerdem dürfte mein Drucker ja dann eben ohne Measure/Arrange nicht fehlerfrei drucken, richtig?

Das mit der Message Box hinkt ein wenig, denn das die Properties richtig gefüllt sind, heisst noch nicht das die Properties auch richtig gebunden sind. Aber mit der 2. Aussage hast Du recht es dürfte dann mit gar keinem Drucker funktionieren. Und hier bin ich nun leider auch mit meinem Latein am Ende (nicht das ich Latein in irgendeiner Form könnte 😉 )

edit: wann und wo setzt Du deinen DataContext auf this?

D
dr0n3 Themenstarter:in
4 Beiträge seit 2013
vor 10 Jahren

Den DataContext setze ich direkt im Konstruktur.


public ListPrint()
{
     InitializeComponent();
    mainGrid.DataContext = this; // <- hier

    dt.Columns.Add("Number");
    dt.Columns.Add("LastName");
    dt.Columns.Add("FirstName");
    dt.Columns.Add("Gender");
    dt.Columns.Add("SchoolClass");
    dt.Columns.Add("Note");

    Date = string.Format("{0:dd.MM.yyyy}", System.DateTime.Today);
    dataGrid.ItemsSource = DataT.DefaultView; // <- und hier
}

Ich weiß nun nicht, ob ich in meinen jungen Jahren schon senil werde, aber ohne bewusste Änderung am Code meinerseits hat sich das Programm nun dazu entschieden, den Header (Überschrift, Datum, Lehrer...) zu drucken. Sowohl bei mir als auch bei Anderen.

Nun gibt es also lediglich eine leere Tabelle, welche allerdings bereits die Zeilen für den Inhalt besitzt. (siehe Bild oben..leere Tabelle, aber Zeilen vorhanden.)
Diese wird mit folgender Funktion befüllt:


public void AddStudent(StudentViewModel vm)
        {
            int number = dt.Rows.Count;

            DataRow dr = dt.NewRow();
            dr["Number"] = number;
            dr["LastName"] = vm.LastName;
            dr["FirstName"] = vm.FirstName;
            dr["Gender"] = vm.Gender;
            dr["SchoolClass"] = vm.SchoolClass;
            bool isInserted = false;

            // sortiert den Schüler in alphabetischer Reihenfolge in die Tabelle ein
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                string studentname = Convert.ToString(dt.Rows[i]["LastName"]);

                if (studentname.CompareTo(vm.LastName) > 0)
                {
                    dt.Rows.InsertAt(dr, i);
                    isInserted = true;

                    break;
                }
            }

            if (!isInserted)
            {
                // füge den Schüler ein am Ende ein, wenn nicht sortiert werden muss
                dt.Rows.Add(dr);
                MessageBox.Show(dr["LastName"].ToString()); // <- Ausgabe erfolgt hier mit korrekten Daten
            }

            // die Nummern der Schüler wieder richten
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                dt.Rows[i]["Number"] = i + 1;
            }

            // update die Zähler
            if (vm.Gender == StudentViewModel.Sex.M)
            {
                Male++;
            }
            else
            {
                Female++;
            }

            Quantity++;

        }