none
WPFで印刷するときにXamlで指定した内容で印刷したいのですが、うまくいきません RRS feed

  • 質問

  • お世話になります。

    Xamlに配置した内容で印刷したいのですが、下記Xaml内のBody部分の内容が「WpfHoken.SeikyuListPrintBody」の1行のみの印字でXamlで指定した通り印刷しません。上下のヘッダー、フッターは印字します。Modelなどには各データが入っています。

    VS2015 C# WPF

    以下がコードです。長くてすみません。

    Xaml

    <Page x:Class="WpfHoken.PrintSeikyuPage"
          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:local="clr-namespace:WpfHoken"
          xmlns:app="clr-namespace:WpfHoken"
          mc:Ignorable="d" 
          d:DesignHeight="300" d:DesignWidth="300"
          Title="請求書印刷">
    
        <Page.Resources>
            <DataTemplate DataType="{x:Type app:SeikyuListPrintBody}">
                <StackPanel>
                <!--    <Grid TextElement.FontSize="20" TextElement.FontWeight="Bold">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="500" />
                            <ColumnDefinition Width="200" />
                        </Grid.ColumnDefinitions>
                        <Border Grid.Column="0" BorderBrush="Black" BorderThickness="1,1,1,1" >
                            <TextBlock Text="ProductName" HorizontalAlignment="Center"/>
                        </Border>
                        <Border Grid.Column="1" BorderBrush="Black" BorderThickness="0,1,1,1" >
                            <TextBlock Text="Price" HorizontalAlignment="Center"/>
                        </Border>
                    </Grid> -->
                    <ItemsControl ItemsSource="{Binding Path=Items}" TextElement.FontSize="12">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate >
                                <Grid >
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="21*" />
                                        <!-- ヘッダ -->
                                        <RowDefinition Height="25*" />
                                        <!-- 金額部分 -->
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="113*" />
                                        <!-- 発行年月日 -->
                                        <ColumnDefinition Width="71*" />
                                        <!-- 御得意先 -->
                                        <ColumnDefinition Width="54*" />
                                        <!-- 担当 -->
                                        <ColumnDefinition Width="54*" />
                                        <!-- 区分 -->
                                        <ColumnDefinition Width="97*" />
                                        <!-- 伝票No. -->
                                    </Grid.ColumnDefinitions>
    
                                    <Rectangle Grid.RowSpan="2" Grid.ColumnSpan="5" RadiusY="5" RadiusX="5" Stroke="Black" />
                                    <Border BorderBrush="Black" BorderThickness="0,1,0,0" Grid.ColumnSpan="5" Grid.Row="1" />
                                    <Border BorderBrush="Black" BorderThickness="1,0,0,0" Grid.RowSpan="2" Grid.Column="1" />
                                    <Border BorderBrush="Black" BorderThickness="1,0,0,0" Grid.RowSpan="2" Grid.Column="2" />
                                    <Border BorderBrush="Black" BorderThickness="1,0,0,0" Grid.RowSpan="2" Grid.Column="3" />
                                    <Border BorderBrush="Black" BorderThickness="1,0,0,0" Grid.RowSpan="2" Grid.Column="4" />
    
                                    <Label Content="発 行 年 月 日" Padding="2" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="0" />
                                    <Label Content="項目名" Padding="2" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="1" />
                                    <Label Content="点 数" Padding="2" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="2" />
                                    <Label Content="件 数" Padding="2" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="3" />
                                    <Label Content="料 金" Padding="2" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Column="4" />
    
                                   <!-- <Label Content="{Binding Path=,StringFormat=yyyy.MM.dd}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Padding="1" Grid.Row="1" Grid.Column="0" />  -->
                                    <Label Content="{Binding Path=KomokuMei}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Padding="1" Grid.Row="1" Grid.Column="1"  />
                                    <Label Content="{Binding Path=Tensu,StringFormat={}\\{0:N}}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Padding="1" Grid.Row="1" Grid.Column="2"  />
                                    <Label Content="{Binding Path=Kensu,StringFormat={}\\{0:N}}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Padding="1" Grid.Row="1" Grid.Column="3"  />
                                    <Label Content="{Binding Path=Ryokin,StringFormat={}\\{0:N}}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Padding="1" Grid.Row="1" Grid.Column="4"  />
                                </Grid>
    
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </StackPanel>
            </DataTemplate>
    
        </Page.Resources>
    
        <Grid Margin="30">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
    
            <Grid Grid.Row="0" x:Name="headerGrid">
                <Border BorderBrush="Black" BorderThickness="0,1" Margin="0,0,0,10">
                    <ContentPresenter Content="{Binding  Path=Header}" HorizontalAlignment="Center" TextElement.FontSize="20"/>
                </Border>
            </Grid>
    
            <Grid Grid.Row="1" x:Name="body">
                <ContentPresenter Content="{Binding Path=Body}" HorizontalAlignment="Center"/>
            </Grid>
    
            <Grid Grid.Row="2" x:Name="footerGrid">
                <Border BorderBrush="Black" BorderThickness="0,1">
                    <StackPanel Margin="0,10,0,0">
                        <ContentPresenter Content="{Binding  Path=Footer}" HorizontalAlignment="Center"/>
                        <TextBlock HorizontalAlignment="Center" Text="{Binding Path=PageNumber,StringFormat={}Page.{0}}"/>
                    </StackPanel>
                </Border>
            </Grid>
        </Grid>
    
    </Page>
    

    そのビハインドコード

    namespace WpfHoken { /// <summary>CD一覧印刷の本文部分のモデル</summary> class SeikyuListPrintBody : ListPrintBodybase<SeikyuData> { } /// <summary> /// PrintSeikyuPage.xaml の相互作用ロジック /// </summary> public partial class PrintSeikyuPage : Page { public PrintSeikyuPage() { InitializeComponent(); } } /// <summary>CD一覧印刷の1ページ分のモデル</summary> class SeikyuListPrintPageModel : PrintPageModelBase { /// <summary>1ページの項目数</summary> public const int CountPerPage = 20; public SeikyuListPrintPageModel(string header, string footer, int pageNumber, IEnumerable<SeikyuData> list) { this.Header = header; this.Footer = footer; this.PageNumber = pageNumber; this.Body = new SeikyuListPrintBody() { Items = list }; } private static IEnumerable<SeikyuListPrintPageModel> CreatePageModels(IEnumerable<SeikyuData> cds, string header = null, string footer = null) { int count = (cds.Count() + CountPerPage - 1) / CountPerPage; for (int i = 0; i < count; i++) { //1ページ分を取り出し var items = cds.Skip(CountPerPage * i).Take(CountPerPage); //印刷用モデルを作る SeikyuListPrintPageModel model = new SeikyuListPrintPageModel(header, footer, i + 1, items); yield return model; } } /// <summary>一覧から印刷用モデルを順番に生成</summary> public static IEnumerable<System.Windows.Controls.Page> CreatePages(IEnumerable<SeikyuData> cds, string header = null, string footer = null) { foreach (SeikyuListPrintPageModel model in CreatePageModels(cds, header, footer)) { PrintPage pp = new PrintPage(); pp.DataContext = model; yield return pp; } } } class SeikyuData { public string KomokuCD { get; set; } public string DateKey { get; set; } public string DateGroupKey { get; set; } public string KomokuMei { get; set; } public string StdID { get; set; } public string UserID { get; set; } public string Sequence { get; set; } public int Kensu { get; set; } // 委託先料金で確認のため public string KensuItaku { get; set; } public int Tensu { get; set; } public int Ryokin { get; set; } public int RyokinItaku { get; set; } // 委託先の単価 public int TankaItaku { get; set; } public int zRyokin { get; set; } public int Gaichu { get; set; } public string Coment { get; set; } public bool CalcLock { get; set; } public string CenterCode { get; set; } } /// <summary>通常のViewModelのようなもの</summary> class PrintSeikyuViewModel { public PrintSeikyuViewModel() { Items = new System.Collections.ObjectModel.ObservableCollection<SeikyuData>(); } public System.Collections.ObjectModel.ObservableCollection<SeikyuData> Items { get; private set; } /// <summary>ダミーデータを作る</summary> public static PrintSeikyuViewModel MakeSeikyu(string dataGroupKey) { PrintSeikyuViewModel model = new PrintSeikyuViewModel(); //System.Random rnd = new System.Random(); WpfHoken.AccountDataDataSetTableAdapters.SeikyuKomokuMasterTableTableAdapter SeikyuKomokuTableAdapter = new AccountDataDataSetTableAdapters.SeikyuKomokuMasterTableTableAdapter(); WpfHoken.AccountDataDataSetTableAdapters.KomokuTableTableAdapter komokuTableAdapter = new AccountDataDataSetTableAdapters.KomokuTableTableAdapter(); DataTable data = SeikyuKomokuTableAdapter.GetDataByGroupKey(dataGroupKey); if (data.Rows.Count > 0) { for (int k = 0; k < data.Rows.Count; k++) { bool calc = false; string txt = data.Rows[k][12].ToString(); if (txt.ToUpper() == "TRUE") calc = true; string kom = data.Rows[k][0].ToString(); DataTable dt = komokuTableAdapter.GetDataBy(kom); SeikyuData seikyu = new SeikyuData(); seikyu.KomokuCD = data.Rows[k][0].ToString(); seikyu.DateKey = data.Rows[k][1].ToString(); seikyu.DateGroupKey = data.Rows[k][2].ToString(); seikyu.UserID = data.Rows[k][3].ToString(); seikyu.StdID = data.Rows[k][4].ToString(); seikyu.Sequence = data.Rows[k][5].ToString(); seikyu.KomokuMei = dt.Rows[0][4].ToString(); int result = 0; if (int.TryParse(data.Rows[k][6].ToString(), out result)) seikyu.Kensu = result; if (int.TryParse(data.Rows[k][7].ToString(), out result)) seikyu.Tensu = result; if (int.TryParse(data.Rows[k][8].ToString(), out result)) seikyu.Ryokin = result; if (int.TryParse(data.Rows[k][9].ToString(), out result)) seikyu.zRyokin = result; if (int.TryParse(data.Rows[k][10].ToString(), out result)) seikyu.Gaichu = result; seikyu.Coment = data.Rows[k][11].ToString(); seikyu.CalcLock = calc; seikyu.CenterCode = data.Rows[k][13].ToString(); model.Items.Add(seikyu); } } return model; } } }

    印刷のコア部分

        /// <summary>印刷ページの基本モデル</summary>
        class PrintPageModelBase
        {
            public object Header { get; set; }
            public object Body { get; set; }
            public object Footer { get; set; }
            public int PageNumber { get; set; }
    
            public static void Print(IEnumerable<System.Windows.Controls.Page> pages)
            {
                FixedDocument doc = new FixedDocument();
                foreach (System.Windows.Controls.Page p in pages)
                {
                    FixedPage fp = CreateFixedPage(p);
                    PageContent pc = new PageContent();
                    pc.Child = fp;
                    doc.Pages.Add(pc);
                }
    
                PrintDialog dlg = new System.Windows.Controls.PrintDialog();
    
                if (dlg.ShowDialog() == true)
                {
                    System.Windows.Xps.XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(dlg.PrintQueue);
    
                    doc.PrintTicket = dlg.PrintTicket;
                    xpsdw.Write(doc, dlg.PrintTicket);
                }
            }
    
            private static FixedPage CreateFixedPage(Page page)
            {
                Action dummy = () => { };
                var disp = System.Windows.Threading.Dispatcher.CurrentDispatcher;
    
                FixedPage fixpage = new FixedPage();
                {
                    Frame fm = new Frame();
    
                    fm.Content = page;
                    //disp.Invoke(dummy, System.Windows.Threading.DispatcherPriority.Loaded);//バインディングとかいろいろさせる必要がある場合
    
                    FixedPage.SetLeft(fm, 0);
                    FixedPage.SetTop(fm, 0);
    
                    fixpage.Children.Add(fm);
    
                    page.Width = 11.69 * 96;
                    page.Height = 8.27 * 96;
    
                    Size sz = new Size(page.Width, page.Height);
    
                    fixpage.Width = page.Width;
                    fixpage.Height = page.Height;
    
                    fixpage.Measure(sz);
                    fixpage.Arrange(new Rect(new Point(), sz));
                    fixpage.UpdateLayout();
                }
                return fixpage;
            }
        }
    
        /// <summary>複数項目印刷する印刷ページの本文部分</summary>
        class ListPrintBodybase<T>
        {
            public IEnumerable<T> Items { get; set; }
        }
    


    2017年2月3日 2:11

すべての返信

  • こんにちは。

    ソースコードもう少し小さくした状態で提示できないでしょうか。
    関係ありそうなところ、なさそうなところを削って試した形跡がないので、
    そのあたりはご質問前にやるべきだと思います。

    さて、以下について教えてください。

    • 印刷時とのことでしたが、このページを画面表示した場合は正しくBodyが表示されるのですか。
    • DataTemplateを用いていますが、DataTemplateを使わずにContentPresenterに直接UI構成を記述した場合は表示されますか。
    2017年2月3日 2:24
    モデレータ
  • お世話になります。

    > 印刷時とのことでしたが、このページを画面表示した場合は正しくBodyが表示されるのですか。

    表示されていません。

    > DataTemplateを用いていますが、DataTemplateを使わずにContentPresenterに・・

    正しいやり方なのか分かりませんが、別ウインドウを作り、

            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center">
                <ContentPresenter.ContentTemplate>
                <DataTemplate >
                    <Grid >
                        <Grid.RowDefinitions>
                            <RowDefinition Height="21*" />
                            <!-- ヘッダ -->
                            <RowDefinition Height="25*" />
                            <!-- 金額部分 -->
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>

                  :

    でなら、表示しています。ただ、データバインドがわからず苦慮しています。

    2017年2月3日 3:26
  • では印刷部分は関係ないですね。

    ContentPresenterの代わりにDataTemplate内のGridをそのまま配置してみてください。
    その場合も表示されないと思いますけど。

    そのようにしてまずは問題と関係のないロジックを極力削ってください。
    その過程で問題が解決することも多々ありますし、解決しなかったとしても質問する上で回答を得やすくなります。

    2017年2月3日 3:29
    モデレータ
  • たぶんこれを参考にしてるんだと思いますが、コメントアウトしてるところを戻してください。

    private static FixedPage CreateFixedPage(Page page)
    {
        Action dummy = () => { };
        var disp = System.Windows.Threading.Dispatcher.CurrentDispatcher;
    
        FixedPage fixpage = new FixedPage();
        {
            Frame fm = new Frame();
    
            fm.Content = page;
    
            //*** ここが重要 ***
            disp.Invoke(dummy, System.Windows.Threading.DispatcherPriority.Loaded);//バインディングとかいろいろさせる必要がある場合
    
    //略
    Frameに読み込まれるのですが、読込完了しないと表示されないのですよ。

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2017年2月3日 3:43
  • お世話になります。

    コメントアウト部分を外しましたが、現状変わりありません。

    Page.Resourcesで囲まれた内容は、表示されません。

    その下の<Grid Margin="30">から囲まれた範囲のみの表示です。

    現在ここまでの確認しかできておりません。

    2017年2月4日 0:53
  • 投稿するときの編集ミスかなと思ったので指摘してなかったのですが、

    /// <summary>一覧から印刷用モデルを順番に生成</summary>
    public static IEnumerable<System.Windows.Controls.Page> CreatePages(IEnumerable<SeikyuData> cds, string header = null, string footer = null)
    {
        foreach (SeikyuListPrintPageModel model in CreatePageModels(cds, header, footer))
        {
            PrintPage pp = new PrintPage();
            pp.DataContext = model;
            yield return pp;
        }
    }

    でPintPageではなくPrintSeikyuPageを返さないといけないですが合ってますか?

    #昼休み時間内でいそいでたので回答がちょっと手抜きだったかも


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2017年2月4日 1:20
  • gekkaさま、

    > PrintPage pp = new PrintPage();
    > でPintPageではなくPrintSeikyuPageを返さないといけないですが合ってますか?

    ご指摘の通りで枠やタイトルなど見出しを含めた表が印字されました。ありがとうございます。

    でも、バインドされているはずのデータ部分が、枠を含めて印字されません。

    枠がつぶれたように下の腺が二重に表示されます。

    もう少し、ご指導いただけますでしょうか?よろしくお願いします。

    2017年2月4日 2:38