WPF Checkbox state does not update in FixedPage

2019-05-09 23:54发布

问题:

I am trying to export a some data based on a FixedPage element used as template in WPF and I seem to have problems updating the value of the checkboxes. The weird part is that I am also using Textblocks and Textboxes in my template, but these have no problem updating their content.

So... from the beginning. The data I want to export is in a class called RepairStatement, which allows printing to a custom xps file using the printForm function.

    public class RepairStatement
{
    // Variables
    public bool hasKulanz { get; set; }
    public bool hasRepair { get; set; }
    public Client client { get; set; }

    /// <summary>
    /// Export repair statement to XPS file. 
    /// </summary>
    /// <param name="file">output xps file</param>
    public void printForm(string file)
    {
        string printTemplateRepairStatementPath = "Print Templates\\RepairStatement.xaml";

        // Define general purpose handlers to be used in browsing the print templates
        FileStream fileStream;

        if (!File.Exists(file))
        {
            FileStream newfile = File.Create(file);
            newfile.Close();
        }

        // Check that all xaml templates exist
        if (!File.Exists(printTemplateRepairStatementPath))
        {
            throw new ArgumentNullException(printTemplateRepairStatementPath, 
                "Repair Statement print template is not available. Check file source");
        }

        FixedDocument doc = new FixedDocument();
        // A4 Standard: 8.27 x 11.69 inch; 96 dpi
        Size documentSize = new Size(96 * 8.27, 96 * 11.69);
        doc.DocumentPaginator.PageSize = documentSize;

        // 1. Reparatur-Bericht
        //  a. Open the filestream
        try
        {
            fileStream = new FileStream(printTemplateRepairStatementPath, FileMode.Open);
        }
        catch (Exception e)
        {
            throw new ArgumentNullException(LoginAgent.userSerializationPath,
                "Repair Statement print template could not be open due to " + e.Message);
        }

        //  b. Read the XAML tree
        FixedPage fixedPage = XamlReader.Load(fileStream) as FixedPage;

        //  c. Set the data
        (fixedPage.FindName("receiptAddress") as TextBox).Text = client.receiptAddress; // Works
        (fixedPage.FindName("deliveryAddress") as TextBox).Text = client.deliveryAddress;// Works
        (fixedPage.FindName("hasEndorser") as CheckBox).IsChecked = true;  // Has no effect

        //  d. Set the page size
        fixedPage.Width = doc.DocumentPaginator.PageSize.Width;
        fixedPage.Height = doc.DocumentPaginator.PageSize.Height;

        // Add to document
        PageContent pageContent = new PageContent();
        ((IAddChild)pageContent).AddChild(fixedPage);
        doc.Pages.Add(pageContent);

        // Convert to XPS
        XpsDocument xpsDocument = new XpsDocument(file, FileAccess.Write);
        XpsDocumentWriter documentWriter = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
        documentWriter.Write(doc);
        xpsDocument.Close();
    }
}

The xaml template I am using looks like this:

<FixedPage xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       Name="RepairStatementFixedPage"
       Background="White"
       Width="793.92" Height="1122.24" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Border Name="bigPage" BorderThickness="1" BorderBrush="#FFCB9999" Width="793.92" Height="1122.24" 
        HorizontalAlignment="Center" VerticalAlignment="Center">
  <Border Name="content" Margin="96, 96">
    <DockPanel LastChildFill="False">
        <Grid DockPanel.Dock="Top" Name="title">
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="120" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="120" />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="10" />
            <RowDefinition Height="*" />
          </Grid.RowDefinitions>
            <Image Grid.Column="0" Grid.RowSpan="3" Width="120" 
              Source="/DesktopLibrarian;component/Content/lib-bg.jpg"
              VerticalAlignment="Top" HorizontalAlignment="Left" />
            <TextBlock Grid.Column="1" Grid.RowSpan="3" HorizontalAlignment="Center" VerticalAlignment="Bottom" 
              TextBlock.FontSize="23">
              Reparaturbericht
            </TextBlock>
            <TextBlock Grid.Column="2" Grid.Row="0" Grid.RowSpan="3" 
              VerticalAlignment="Top" HorizontalAlignment="Right" Name="repairNumber">
              TEST
            </TextBlock>
        </Grid>
        <Border DockPanel.Dock="Top" Height="20" />
        <Grid DockPanel.Dock="Top" Name="deviceInfo">
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
          </Grid.RowDefinitions>
        </Grid>

        <!-- Client information --> 
        <GroupBox DockPanel.Dock="Top" Header="Kundeninformationen">
          <Grid Margin="3">
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="130" />
              <ColumnDefinition Width="3" />
              <ColumnDefinition Width="110" />
              <ColumnDefinition Width="8" />
              <ColumnDefinition Width="*" />
              <ColumnDefinition Width="8" />
              <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
              <RowDefinition Height="Auto" />
              <RowDefinition Height="Auto" />
              <RowDefinition Height="Auto" />
              <RowDefinition Height="Auto" />
              <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <!-- Name -->
            <TextBlock Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="0" Name="clientName" 
              TextBlock.FontWeight="Bold">
              TEST
            </TextBlock>

            <!-- Phone Number -->
            <TextBlock Grid.Column="0" Grid.Row="2">Telefonnummer:</TextBlock>
            <TextBlock Grid.Column="2" Grid.Row="2" Name="phoneNumber">TEST</TextBlock>

            <!-- Auftragsnummer -->
            <TextBlock Grid.Column="0" Grid.Row="3">Auftragsnummer (RMA):</TextBlock>
            <TextBlock Grid.Column="2" Grid.Row="3" Name="orderNumber">TEST</TextBlock>

            <!-- Receipt Address -->
            <TextBlock Grid.Column="4" Grid.Row="1">Rechnungsadresse:</TextBlock>
              <TextBox Grid.Column="4" Grid.Row="2" Grid.RowSpan="2" Name="receiptAddress" BorderThickness="0"
                 AcceptsReturn="True" TextWrapping="Wrap">
                TEST
              </TextBox>

            <!-- Delivery Address -->
            <TextBlock Grid.Column="6" Grid.Row="1">Lieferadresse:</TextBlock>
              <TextBox Grid.Column="6" Grid.Row="2" Grid.RowSpan="2" Name="deliveryAddress" BorderThickness="0"
                 AcceptsReturn="True" TextWrapping="Wrap">
                TEST
              </TextBox>
          </Grid>
        </GroupBox>
        <Border DockPanel.Dock="Top" Height="20" />

        <!-- Device information -->
        <GroupBox DockPanel.Dock="Top" Header="Geräteinformationen">
          <Grid Margin="3">
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="90" />
              <ColumnDefinition Width="3" />
              <ColumnDefinition Width="150" />
              <ColumnDefinition Width="8" />
              <ColumnDefinition Width="*" />
              <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
              <RowDefinition Height="Auto" />
              <RowDefinition Height="Auto" />
              <RowDefinition Height="Auto" />
              <RowDefinition Height="Auto" />
              <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>

            <!-- Model -->
            <TextBlock Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="0" Name="model" TextBlock.FontWeight="Bold">
              TEST
            </TextBlock>

            <!-- Repair -->
            <CheckBox Grid.Column="4" Grid.Row="1" Name="hasRepair">Reparatur</CheckBox>

            <!-- Device has endorser -->
            <CheckBox Grid.Column="4" Grid.Row="2" Name="hasEndorser">Endorsergerät</CheckBox>
          </Grid>
        </GroupBox>

    </DockPanel>
  </Border>
</Border>

The problem is in these 3 lines from the printForm function:

            //  c. Set the data
        (fixedPage.FindName("receiptAddress") as TextBox).Text = client.receiptAddress;
        (fixedPage.FindName("deliveryAddress") as TextBox).Text = client.deliveryAddress;
        (fixedPage.FindName("hasEndorser") as CheckBox).IsChecked = true;

The first two lines modify the content of the textbox as normal. I can also modify the content of Textblocks without problems, but the values for the checkboxes do not change, no matter what I try to do. I assume it is something to do with FixedPage or FixedDocument, but I cannot fathom what the problem may be. If I set IsChecked="True" in XAML the checkbox will appear as checked in the final xps document, but similarly I cannot uncheck it.

Any hints as to what might be going wrong would be greatly appreciated. If you know of good tutorials or information sources for FixedPage and FixedDocument I would love to have a look at them as well, since the documentation I have found so far is modest to say the least.

Thanks!

Update: I also asked the question on the msdn forums here and got some hint about using Measure(), Arrange and updatelayout() before exporting to xps. Unfortunately this solution doesn't seem to work. I do think it would have been a far shot, considering that textblock and textbox elements behave as expected and I only have problems with checkboxes.

And I decided to make a small project that shows the bug so that you can also experiment a bit on your own. You can find it here.

Let me know if you figure something out :D

回答1:

I have found the problem and I have also found some beginning of a solution.

Apparently enabled checkboxes do not check when exported to wpf. I guess the developers' idea when they wrote the code is that enabled checkboxes on a piece of paper should only be checked by hand. Most unfortunately for me, I want to check them programmatically.

I have also found some solution to this problem. Disabled checkboxes are shown as checked and unchecked. With the major drawback of course that they're all greyed out, like disabled checkboxes are supposed to look like.

Well... I guess it's time to figure out how to restyle my disabled checkboxes to look like they're enabled. Hmmm.... maybe printing five of them on top of each other? Fingers crossed!



回答2:

The same issue happens with RadioButtons. I solved it by displaying my FixedDocument in PrintPreview window before printing (using DocumentViewer) (link: http://www.nbdtech.com/Blog/archive/2009/07/09/wpf-printing-part-4-ndash-print-preview.aspx).

EDIT: Coming back to this question almost half a year later. The requirement for my application changed, and I had to implement silent printing, which no longer allowed me to use PrintPreview window workaround mentioned above. The solution ended up being similar to the one mentioned in the other answer. I ended up adding custom checkbox/radiobutton template, and disabling IsEnabled style triggers. The issue is finding Aero BulletChrome template. The following question helped in that respect https://stackoverflow.com/a/24863563/1288473