Autor Beitrag
IsNull
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 97
Erhaltene Danke: 11


VS 2010, C#, AHK
BeitragVerfasst: Mi 29.06.11 09:56 
Hallo Gemeinde,

Im Zuge vom erstellen eines Rapport-Systems in WPF bin ich auf ein Problem beim dynamischen Laden von xaml Controls gestossen. Ich weis nicht ob hier der Teufel im Detail liegt, oder ob ich da ein Grundsätzliches Verständnisproblem habe.

Zunächstmal, ich möchte die Rapporte mit einem Flowdocument darstellen/generieren aber das ganze mit DataBinding nutzen. Dazu hat Vincent Van Den Berghe einen netten Artikel verfasst msdn.microsoft.com/e...gazine/dd569761.aspx, und ich habe das ganze so adaptiert.

Das ganze funktioniert nun auch, wenn ich einen Rapport als UserControl definiere und dieses dann im Codebehind lade:

ausblenden volle Höhe XML-Daten
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
<UserControl x:Class="Company.ViewModel.Templates.SomeTest"
             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" 
             xmlns:flowdoc="clr-namespace:Archimedes.Patterns.WPF.FlowDocuments;assembly=Archimedes.Patterns.WPF"
             Background="White"
             mc:Ignorable="d" 
             d:DesignHeight="669" d:DesignWidth="588">
    
    <FlowDocument 
              PageHeight="29.7cm" PageWidth="21cm" ColumnWidth="21cm">

        <Paragraph>
            <Bold>Mein schöner Rapport</Bold>
        </Paragraph>


        <flowdoc:ItemsContent ItemsSource="{Binding AllCustomers}" >
            <flowdoc:ItemsContent.ItemsPanel>
                <DataTemplate>
                    <flowdoc:Fragment>
                        <Table BorderThickness="1" BorderBrush="Black">
                            <TableRowGroup flowdoc:Attached.IsItemsHost="True">
                                <TableRow Background="LightBlue">
                                    <TableCell>
                                        <Paragraph>Customer</Paragraph>
                                    </TableCell>
                                    <TableCell>
                                        <Paragraph>Last visit</Paragraph>
                                    </TableCell>
                                </TableRow>
                            </TableRowGroup>
                        </Table>
                    </flowdoc:Fragment>
                </DataTemplate>

            </flowdoc:ItemsContent.ItemsPanel>
            <flowdoc:ItemsContent.ItemTemplate>
                <DataTemplate>
                    <flowdoc:Fragment>
                        <TableRow>
                            <TableCell>
                                <Paragraph>
                                    <flowdoc:BindableRun BoundText="{Binding MatchCode}" />
                                </Paragraph>
                            </TableCell>
                            <TableCell>
                                <Paragraph>
                                    <flowdoc:BindableRun BoundText="{Binding LastSalesmanVisit}"/>
                                </Paragraph>
                            </TableCell>
                        </TableRow>
                    </flowdoc:Fragment>
                </DataTemplate>
            </flowdoc:ItemsContent.ItemTemplate>
        </flowdoc:ItemsContent>

    </FlowDocument>
</UserControl>

Zu beachten ist, das die interessante Klasse flowdoc:ItemsContent 1:1 der aus dem oben verlinkten Artikel entspricht. --> msdn.microsoft.com/e...69761.aspx#id0420102


Mit dem UserControl als "DataTemplate" ist das nun aber leider nicht dynamisch. Was ich will, ist schlicht eine simple xaml Datei (ohne Codebehind), welche als root element das FlowDocument hat:

SalesmanRouteRapport.xaml
ausblenden volle Höhe XML-Daten
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
    
    <FlowDocument 
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" 
             xmlns:flowdoc="clr-namespace:Archimedes.Patterns.WPF.FlowDocuments;assembly=Archimedes.Patterns.WPF"
              PageHeight="29.7cm" PageWidth="21cm" ColumnWidth="21cm">

        <Paragraph>
            <Bold>Mein schöner Rapport</Bold>
        </Paragraph>


        <flowdoc:ItemsContent ItemsSource="{Binding AllCustomers}" >
            <flowdoc:ItemsContent.ItemsPanel>
                <DataTemplate>
                    <flowdoc:Fragment>
                        <Table BorderThickness="1" BorderBrush="Black">
                            <TableRowGroup flowdoc:Attached.IsItemsHost="True">
                                <TableRow Background="LightBlue">
                                    <TableCell>
                                        <Paragraph>Customer</Paragraph>
                                    </TableCell>
                                    <TableCell>
                                        <Paragraph>Last visit</Paragraph>
                                    </TableCell>
                                </TableRow>
                            </TableRowGroup>
                        </Table>
                    </flowdoc:Fragment>
                </DataTemplate>

            </flowdoc:ItemsContent.ItemsPanel>
            <flowdoc:ItemsContent.ItemTemplate>
                <DataTemplate>
                    <flowdoc:Fragment>
                        <TableRow>
                            <TableCell>
                                <Paragraph>
                                    <flowdoc:BindableRun BoundText="{Binding MatchCode}" />
                                </Paragraph>
                            </TableCell>
                            <TableCell>
                                <Paragraph>
                                    <flowdoc:BindableRun BoundText="{Binding LastSalesmanVisit}"/>
                                </Paragraph>
                            </TableCell>
                        </TableRow>
                    </flowdoc:Fragment>
                </DataTemplate>
            </flowdoc:ItemsContent.ItemTemplate>
        </flowdoc:ItemsContent>

    </FlowDocument>



Die Frage ist nun, wie ich das Ding gescheit lade. Rein theoretisch sollte folgendes geschehen:

1. FlowDocument dynamisch laden
2. Datenkontext setzten -> daraufhin sollte dann flowdoc:ItemsContent mit dem Binding die Elemente generieren.
3. Das ganze in eine FixedDocumentSequence verwandeln, was dann zum anzeigen verwendet wird.


Meine Versuche, teils basierend auf vorhandenen Raport lösungen:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
        FixedDocumentSequence CreateRouteRapport(SalesmanRouteViewModel routeVM) {
            var flowDoc = DocHelpers.LoadFlowDocumentFromFile(@"Templates\SalesmanRouteRapport.xaml");
            //var flowDoc = DocHelpers.LoadFlowDocumentFromFile(@"Templates\TestRapport.xaml");
            flowDoc.DataContext = routeVM;

            var xpsdoc = DocHelpers.CreateXpsDocument(flowDoc);

            return xpsdoc.GetFixedDocumentSequence();
        }


Und die beiden Interessanten Methoden in DocHelper:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
   public static class DocHelper
{
 ;....

 public static FlowDocument LoadFlowDocumentFromFile(string filePathXaml) {
            FlowDocument doc;
            using (StreamReader sr = new StreamReader(new FileStream(filePathXaml, FileMode.Open, FileAccess.Read))) {
                doc = XamlReader.Load(sr.BaseStream) as FlowDocument;
                sr.Close();
            }
            return doc;
        }

        public static XpsDocument CreateXpsDocument(FlowDocument document) {
            MemoryStream ms = new MemoryStream();
            Package pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
            string pack = "pack://report.xps";
            PackageStore.RemovePackage(new Uri(pack));
            PackageStore.AddPackage(new Uri(pack), pkg);
            XpsDocument xpsdoc = new XpsDocument(pkg, CompressionOption.NotCompressed, pack);
            XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(xpsdoc), false);

            DocumentPaginator dp = 
                ((IDocumentPaginatorSource)document).DocumentPaginator;
            rsm.SaveAsXaml(dp);
            return xpsdoc;
        }

   ;....
   }


Als Ergebnis wird das ganze zwar geladen und die statischen Inhalte sind vorhanden, aber mein flowdoc:ItemsContent der die eigentlichen Daten Darstellen soll bleibt leer.

In meinen bisherigen Debug Versuchen habe ich herausgefunden, dass beim dynamischen laden das FlowDocument initialisiert wird, d.h. auch flowdoc:ItemsContent Control wird erstellt. Aber das FlowDocument wird nie geladen. (Irgendwie auch verständlich, es wird auch nie als Kind einem Fenster/anderen Control zugewiesen)

Btw: Insbesondere dies CreateXpsDocument(FlowDocument document) Methode ist nicht von mir, und ich frage mich ob das wirklich sinnvoll ist.

Soweit ich das sehe wird mein FlowDocument also initialisiert, aber nicht "geladen". Und daher funktioniert das mit dem Binding auch nicht.

Any Advice?


Edit:
Cross-Post Verweis:
www.mycsharp.de/wbb2...=3683821#post3683821