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>
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.
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)
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.
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));
}
}
}
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?
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++;
}