How to: Extend the Print Schema and Create New Print System Classes

When your application must deal with specialty print devices that have characteristics not reflected by the existing PrintSystemObject, PrintQueue, PrintCapabilities, and PrintTicket classes, you may want to derive new classes by inheritance, create extended versions of the PrintCapabilities and PrintTicket classes, and possibly also extend the Print Schema. This article describes the major parts of such a project; but it describes one of many ways of extending the relevant managed classes.

We recommend that you read this article in conjunction with the extensive documentation of the Print Schema. This article presupposes that you have at least a basic idea what the schema is and what PrintTicket documents and PrintCapabilities documents are.

This article has the following sections.

  • Derive a New Class by Inheritance

  • Determine Whether the Device's Features are Already Defined in the Print Schema

  • Create Types to Represent Device Features

  • Extending the PrintCapabilities and PrintTicket Classes

    • Extending the PrintTicket Class

    • Extending the PrintCapabilities Class

  • Reading and Writing PrintCapabilities and PrintTicket XML Streams

  • Overloading and Extending Properties and Methods

  • Expanding Schema-Defined Features

  • Extending the System.Printing.IndexedProperties Namespace

Example

The example project presented in this article does not provide all of the details necessary to compile and run an application. It is intended to provide you with a picture of only the major steps needed to extend the functionality of the System.Printing and System.Printing.IndexedProperties namespaces to print devices that have features not explicitly supported in those namespaces. Code examples are provided only where concrete detail is needed.

Also, the code examples do not necessarily include techniques of good programming practices or secure code. Anything not immediately relevant to the subject of the article is omitted.

Finally, this article is addressed primarily to application developers rather than device driver developers. For that reason, the emphasis is on writing PrintTicket objects, rather than PrintCapabilities objects.

Derive a New Class by Inheritance

Begin by deriving a class to represent your device from the PrintQueue class. In the code example below, a BrailleEmbosser class is derived. Braille is a language that is readable by the blind because its symbols are composed of "dots" raised off the surface of the paper so they can be felt with fingertips. A Braille embosser is simply a printer that prints Braille. Some drivers for Braille embossers are able to translate regular Braille into Braille Grade 3, sometimes called Braille 3, which is a space saving version of Braille that uses many contractions and abbreviations. The example provides a property to represent this feature.

Often you will also need to overload some inherited properties and methods. See Overloading and Extending Properties and Methods below for details.

class BrailleEmbosser : PrintQueue
{
   public BrailleEmbosser(PrintServer ps, String s, PrintSystemDesiredAccess access) : base(ps, s, access)
   {
      // Optionally, include here code to set non-inherited fields.
   }

   // other constructor declarations omitted

   private Boolean isBraille3Enabled;

   public Boolean IsBraile3Enabled
   {
      get { return isBraille3Enabled; }
      set { isBraille3Enabled = value; }
   }

   // remainder of class definition omitted
}

Determine Whether the Device's Features are Already Defined in the Print Schema

The PrintTicket and PrintCapabilities classes have properties representing the most common printer features, but there are many more features defined in the Print Schema Public Keywords specification that are not explicitly reflected in those classes. (For a list of the common features, just see the properties of the PrintCapabilities class.) You should read the specification to determine if the device's special features are defined in it. For any feature that is included in the specification, there is a great advantage to using the specification's model: a common model and terminology makes it possible for PrintTicket XML documents created for one device to be used by another. (The second device might be made by a different manufacturer and, for that matter; it might have been designed after the PrintTicket document was originally created.) Print tickets can be embedded in documents themselves so that the author's printing intentions as well as his or her formatting intentions can be carried along as the document is distributed to people with different printers.

For the remainder of this article, features explicitly supported by the PrintTicket and PrintCapabilities classes will be called "common features." Those that are defined in the Print Schema Public Keywords specification, but not explicitly supported by the two classes, will be called "defined features." Features that are not defined in the Public Keywords specification will be called "new features."

It is also possible that your device has a feature that is nearly a perfect match to a defined feature, but it has one or more extra options not recognized in the Print Schema Public Keywords specification. The Print Schema can be extended to handle such features in a way that leverages as much of the existing definition as possible. For more information on how to work with such a feature, see Expanding Schema-Defined Features below.

Create Types to Represent Device Features

The properties of PrintTicket and PrintCapabilities that correspond to printer features take special types, usually enumerations that represent a feature and its possible values. The Collation enumeration for example is the type for the PrintTicket.Collation property. It is also the type of the members of the collection that is the type PrintCapabilities.CollationCapability property.

Create classes for your device's defined and new features using these existing classes as models. In the code sample below, a BrailleGrade3 enumeration is declared. It is constructed on the model of the Collation enumeration because Grade 3 translation is analogous to collating: Any printer would have to support at least one kind of output (collated or uncollated) because they are mutually exhaustive. Some printers support both. (Printers that only support collated output are rare, but that possibility has to be taken into account.) So, too, there can be embossers that support only untranslated Braille output, only translated output (not likely, but possible), or both. The BrailleGrade3 enumeration includes an Unknown value for the same reason that Collation does: to handle situations where a PrintTicket-document-producing application has set the collation feature to a value that is not recognized in the Print Schema Public Keywords specification. If your application creates a PrintTicket object using such a document, then the PrintTicket.Collation property will get the value Unknown. (The Unknown value is never used by PrintCapabilities objects.)

public enum BrailleGrade3 { Translated, Untranslated, Unknown } 

Enumerations are not always the best way to represent a feature. Sometimes a reference type class is better. This is particularly true when the feature has a nested structure of subordinate parts that each have their own value. For example, the PageMediaSize class has Height and Width properties. PageMediaSize is the type of the PrintTicket.PageMediaSize property. It is also the type of the members of the collection that is the type of the PrintCapabilities.PageMediaSizeCapability property.

Extending the PrintCapabilities and PrintTicket Classes

Although the PrintTicket and PrintCapabilities classes cannot be inherited, you can extend the Print Schema to recognize defined and new features.

Extending the PrintTicket Class

To use the PrintTicket class with your extended system of features, take the following steps. Some details are below.

High Level Procedure for Extending the PrintTicket Class

  1. If the device has new features, create a new class to encapsulate the new features. (See Create a NewFeaturesPrintTicket Class for some details.)

  2. If the device has defined features, create a class to encapsulate the defined features. (See Create a DefinedFeaturesPrintTicket Class for some details.)

  3. Create a class to represent a whole print ticket. This class will play the role in your application that the PrintTicket class would play if the device had no defined or new features. (See Create a WholePrintTicket Class for some details.)

Procedure for Creating a NewFeaturesPrintTicket Class

  1. If the device has new features, declare a class to encapsulate those features. Let us call it NewFeaturesPrintTicket.

  2. Give your new class properties to represent the new features of the device. Typically, each property will be of a type that you create, usually an enumeration. See Create Types to Represent Device Features above.

  3. Give the new class an additional property, let us call it PrivateNamespace, that will hold a reference to the private XML namespace that defines the device's new features. You will need this string when writing XML markup to PrintCapabilities and PrintTicket documents. See Reading and Writing PrintCapabilities and PrintTicket XML Streams below.

  4. Give the class two constructors. The constructors should be modeled on the two constructors for PrintTicket. One takes no parameters, the other takes a Stream object with XML content. The XML stream will be a PrintTicket document that defines new, rather than common features. (See Print Schema-Related Technologies and PrintTicket Schema and Document Construction.) The constructors with the parameter should throw exceptions on the pattern of the PrintTicket class's one-parameter constructor.

  5. Create a GetXmlStream and a SaveTo method for the class. Use the access keyword "internal" for both of them These are intended to match the functionality of the PrintTicket methods of those names, except that they will process PrintTicket documents that define new features instead of common features. These methods must ensure that the streams they produce have an extra namespace declaration (the value of the PrivateNamespace property) in the opening <PrintTicket … > element. See Reading and Writing PrintCapabilities and PrintTicket XML Streams below.

Procedure for Creating a DefinedFeaturesPrintTicket Class

  • If the device has defined features, declare a class to encapsulate those features. Let us call it DefinedFeaturesPrintTicket. It should be constructed just as you constructed the NewFeaturesPrintTicket above, with the following exceptions.

    • The properties of the class must have names that match the corresponding feature name in the Print Schema Public Keywords specification.

    • Do not create a PrivateNamespace property. The namespace for defined features is the same as for the common features. See Reading and Writing PrintCapabilities and PrintTicket XML Streams below.

    • The GetXmlStream and SaveTo methods do not produce streams with an extra namespace declaration.

Procedure for Creating a WholePrintTicket Class

  1. Declare a class that will represent a whole print ticket and, thus, will play the role in your application that the PrintTicket class would have played if the device had no defined or new features. Let us call it WholePrintTicket.

  2. Give WholePrintTicket a property, let us call it CommonFeatures, of type PrintTicket.

  3. Give WholePrintTicket one or both of the following additional properties, depending on whether it has new features, defined features, or both.

    • NewFeatures of type NewFeaturesPrintTicket.

    • DefinedFeatures of type DefinedFeaturesPrintTicket.

  4. Give WholePrintTicket two constructors. One that takes no parameters and one that takes a Stream object with XML content. The constructor with a parameter will do the following.

    1. Pass the Stream to the constructor for the PrintTicket object referred to by the CommonFeatures property. That constructor will simply ignore any markup in the Stream that is not relevant to common features.

    2. Pass the Stream to the constructor of the NewFeaturesPrintTicket object referred to by the NewFeatures property. That constructor will simply ignore any markup in the Stream that is not relevant to new features. If there is any new feature markup, then the Stream will begin with <psf:PrintTicket xmlns:psf="https://schemas.microsoft.com/windows/2003/08/printing/printschemaframework" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="https://www.w3.org/2001/XMLSchema" version="1" xmlns:namespace-abbreviation=full-namespace-name>, where full-namespace-name is the URL used to identify the schema that defines the new features and namespace-abbreviation is the abbreviation of it. (For more information, see Reading and Writing PrintCapabilities and PrintTicket XML Streams below.).

    3. Pass the Stream to the constructor of the DefinedFeaturesPrintTicket object referred to by the DefinedFeatures property. That constructor will simply ignore any markup in the Stream that is not relevant to defined features.

  5. Create a GetXmlStream and a SaveTo method for the class. These are intended to match the functionality of the PrintTicket methods of those names. They should have the following characteristics.

    • Each such method should call the corresponding method of the same name in the objects referred to by the CommonFeatures property, the DefinedFeatures property (if there is one) and the NewFeatures property (if there is one).

    • Each method should concatenate the streams produced by the calls described in the previous bullet. Of course, all but the last </PrintTicket> end tag, and all but the first <PrintTicket … > start tag, should be deleted. Unless there are no new features, the start tag should have the extra namespace declaration. (See step 4b.) For that reason, you should consider always making the new features stream (when there is one) the first one in the concatenated stream since it will already have that declaration in its <PrintTicket … > start tag.

    • In order to do the concatenation, the WholePrintTicket’s GetXmlStream and SaveTo methods will need to work on a temporary stream internally first. Specifically, they will have the three different classes each serialize their content into the temporary stream, do the concatenation work (and pruning work - see next bullet), and then output the concatenation result to the final output stream.

    • Following concatenation, the WholePrintTicket’s GetXmlStream and SaveTo methods will also have to remove duplicate and triplicate copies of elements from the stream before returning the final stream. These duplicate and triplicate entries will be in the stream because each the three objects, PrintTicket, NewFeaturesPrintTicket, and DefinedFeaturesPrintTicket, preserve all of the original PrintTicket document that was used to construct it, even though each of them exposes only a subset of the document in its properties.

    • You could avoid the pruning step described in the preceding bullet, if your WholePrintTicket(Stream) constructor -see above- split the incoming stream into three parts by creating separate streams for the common, new, and defined markup elements. Each of these smaller streams is then passed to the appropriate constructor of the three properties of WholePrintTicket. This technique would require you to add a closing </PrintTicket> tag to each of the three streams. To the stream for CommonFeatures and DefinedFeatures properties, you add a start tag like this: <psf:PrintTicket xmlns:psf="https://schemas.microsoft.com/windows/2003/08/printing/printschemaframework" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="https://www.w3.org/2001/XMLSchema" version="1">. The start tag for the NewFeatures property's constructor would add to this an additional private namespace like this: <psf:PrintTicket xmlns:psf="https://schemas.microsoft.com/windows/2003/08/printing/printschemaframework" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="https://www.w3.org/2001/XMLSchema" version="1" xmlns:namespace-abbreviation=full-namespace-name>, where full-namespace-name is the URL used to identify the schema that defines the new features and namespace-abbreviation is the abbreviation of it.)

The following code sample illustrates part of the outcome of this procedure when applied to the Braille embosser example. (For space and simplicity, much has been omitted.) Note that the BrailleGrade3 property is a Nullable<T> type. This follows the pattern of the properties of PrintTicket such as Collation. The example assumes that there are both new and defined features, although it does not specify any particular defined features.

class NewFeaturesPrintTicket
{
    public NewFeaturesPrintTicket()
    {
        // Optionally, initialize fields. For example:
        privateNamespace = "https://www.AjaxEmbossers.com/schemas/deluxemodels/v.1.0";
    }

    public NewFeaturesPrintTicket(Stream printTicketDocument)
    {
    // Parse the stream and initialize fields representing features here.
    // Optionally, initialize other fields. For example:
    privateNamespace = "https://www.AjaxEmbossers.com/schemas/deluxemodels/v.1.0";
    }

    private Nullable<BrailleGrade3> brailleGrade3;
    public Nullable<BrailleGrade3> BrailleGrade3
    {
        get { return brailleGrade3; }
        set { brailleGrade3 = value;}
    }

    private String privateNamespace;
    public String PrivateNamespace
    {
        get { return privateNamespace; }
        set { privateNamespace = value; }
    }
}

class DefinedFeaturesPrintTicket
{
  // Details omitted. Use the NewFeaturesPrintTicket
  // as a model, but leave out the privateNamespace field
  // and property.
}

class WholePrintTicket
{
    public WholePrintTicket()
    {
        commonFeatures = new PrintTicket();
        newFeatures = new NewFeaturesPrintTicket();
        definedFeatures = new DefinedFeaturesPrintTicket();
    }

    public WholePrintTicket(Stream wholePrintTicket)
    {
         // Method 1: Pass the stream to the three constructors.
         // Be sure to reset the read-write position of the stream
         // to the beginning of the stream after each call to a 
         // constructor. 
         // commonFeatures = new PrintTicket(wholePrintTicket);
              // reset read-write head here
        // newFeatures = new NewFeaturesPrintTicket(wholePrintTicket);
              // reset read-write head here
        // definedFeatures = new DefinedFeaturesPrintTicket(wholePrintTicket);
              // reset read-write head here

        // Method 2: Parse the stream and split it into three streams. 
        // Then pass them to the constructors of the three properties. 
        // commonFeatures = new PrintTicket(commonFeaturesPrintTicketDocument);
        // newFeatures = new NewFeaturesPrintTicket(newFeaturesPrintTicketDocument);
        // definedFeatures = new DefinedFeaturesPrintTicket(definedFeaturesPrintTicketDocument);
    }

    private PrintTicket commonFeatures;
    public PrintTicket CommonFeatures
    {
        get { return commonFeatures; }
        set { commonFeatures = value;}
    }

    private PrintTicket newFeatures;
    public PrintTicket NewFeatures
    {   // Details omitted. See CommonFeatures above.}

    private PrintTicket definedFeatures;
    public PrintTicket DefinedFeatures
    {   // Details omitted. See CommonFeatures above.}
}

Extending the PrintCapabilities Class

To use the PrintCapabilities class with your device, you need to extend it in manner that is parallel to how you extended the PrintTicket class. Since you can use your extension of PrintTicket as a model, only a brief overview is presented here.

  • Create three new classes, one to encapsulate new features (NewFeaturesPrintCapabilities), one to encapsulate defined features (DefinedFeaturesPrintCapabilities), and one to represent a whole PrintCapabilities document (WholePrintCapabilities).

  • The types of the properties of the first two new classes will typically be ReadOnlyCollection<T>. Use the existing properties of PrintCapabilities, such as CollationCapability, as models.

  • Also following the pattern of the existing PrintCapabilities class, the property names should have "Capability" on the end; for example, BrailleGrade3Capability.

  • The NewFeaturesPrintCapabilities class will have a PrivateNamespace property identical to the one you created for NewFeaturesPrintTicket.

  • None of the classes will have any methods other than what they inherit from the Object class.

  • Each of the classes will have a single constructor that takes a Stream parameter. The Stream will be a PrintCapabilities document.

  • The DefinedFeaturesPrintCapabilities constructor must validate that the Stream passed to it conforms to the Print Schema Framework before it uses the Stream to initialize properties. (One easy way to do this is to pass the Stream first to the PrintCapabilities constructor. If the latter throws no exceptions, the stream is valid.)

  • The NewFeaturesPrintCapabilities constructor must validate that the Stream passed to it conforms to the private namespace before it uses the Stream to initialize properties.

  • Both of the DefinedFeaturesPrintCapabilities and NewFeaturesPrintCapabilities constructors will throw exceptions on the pattern of the existing PrintCapabilities constructor.

  • The WholePrintCapabilities class will have CommonFeatures, DefinedFeatures, and NewFeatures properties. The types of these properties will be PrintCapabilities, DefinedFeaturesPrintCapabilities, and NewFeaturesPrintCapabilties, respectively. Each will be constructed on the pattern of the properties of WholePrintTicket.

  • The constructor for the WholePrintCapabilities class will take a single Stream parameter representing a whole PrintCapabilities document. The constructor should pass the whole input Stream to all three constructors for its member properties. Since the WholePrintCapabilities class does not have any methods that export its settings in XML format (like the WholePrintTicket’s GetXmlStream and SaveTo methods), the fact that there will be duplicate or triplicate markup within the three properties is harmless.

For additional information, see PrintCapabilities Schema and Document Construction.

Reading and Writing PrintCapabilities and PrintTicket XML Streams

The primary work of the constructors and methods of the existing PrintTicket and PrintCapabilities classes and the new classes you created above in Extending the PrintCapabilities and PrintTicket Classes is to read, parse, write, and sometimes validate Stream objects whose content is either a PrintTicket document or a PrintCapabilities document. You should be familiar with Basic File I/O, and the methods of those classes. Since the content of these streams is XML, you should also familiarize yourself with the XML reading and writing support described in XML Processing Options in the .NET Framework. If your application works with XML Paper Specification (XPS) documents, there are API in the System.Windows.Xps, System.Windows.Xps.Packaging, and System.Windows.Xps.Serialization namespaces designed for reading and writing to XPS documents, including reading and writing PrintTickets. See also PackageRelationship for information on adding a relationship to a PrintTicket into a package.

Full samples of a PrintTicket document and a PrintCapabilities document can be found at PrintTicket Example and PrintCapabilities Document Example.

The following is a simple example of a PrintCapabilities document in which all but one of the device's features has been omitted. The feature shown is DocumentCollate which is the feature that is represented by the PrintCapabilities.CollationCapability and PrintTicket.Collation properties.

<psf:PrintCapabilities xmlns:psf="https://schemas.microsoft.com/windows/2003/08/printing/printschemaframework" 
           xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" 
           xmlns:xsd="https://www.w3.org/2001/XMLSchema" version="1">

   <!-- other features omitted --> 
   
   <psf:Feature name="psk:DocumentCollate">
        <psf:Property name="psf:SelectionType">
            <psf:Value xsi:type="xsd:QName">psk:PickOne</psf:Value>
        </psf:Property>
        <psf:Property name="psk:DisplayName">
            <psf:Value xsi:type="xsd:string">Collate Copies</psf:Value>
        </psf:Property>
        <psf:Option name="psk:Collated" constrained="psk:None">
            <psf:Property name="psk:DisplayName">
                <psf:Value xsi:type="xsd:string">Yes</psf:Value>
            </psf:Property>
        </psf:Option>
        <psf:Option name="psk:Uncollated" constrained="psk:None">
            <psf:Property name="psk:DisplayName">
                <psf:Value xsi:type="xsd:string">No</psf:Value>
            </psf:Property>
        </psf:Option>
    </psf:Feature>
                   
   <!-- other features omitted --> 
   
</PrintCapabilities>

Notice that every possible option of the feature is listed (both collated and uncollated) and the state of each (that is, whether it is constrained or not) is identified. In a complete PrintCapabilities document, the state of every option of every feature is identified, so the document is a kind of snapshot of the configuration of the device.

The following is a simple example of a PrintTicket document that has only a single feature.

<psf:PrintTicket xmlns:psf="https://schemas.microsoft.com/windows/2003/08/printing/printschemaframework" 
           xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" 
           xmlns:xsd="https://www.w3.org/2001/XMLSchema" version="1">
  
  <!-- other features omitted -->
  
  <psf:Feature name="psk:DocumentCollate">
    <psf:Option name="psk:Collated" />
  </psf:Feature>  
    
  <!-- other features omitted -->
  
</PrintTicket>

Notice that the structure can be somewhat simpler because it is not necessary for a PrintTicket document to explicitly specify the state of each option. It needs only to identify the option requested.

The syntax and structure of the feature is defined at DocumentCollate by the Print Schema Framework and the Print Schema Public Keywords. When you are working with new features, you will be working with features defined in a private XML namespace defined in a supplementary schema. Usually this is supplied by the device's manufacturer, by a trade association, or by a non-profit standards organization; but it might be you who creates it. Use the existing the Print Schema Framework and the Print Schema Public Keywords to learn the required syntax and to find models on which you can base your definitions. Microsoft itself created a new namespace in order to extend the PrintCapabilities and PrintTicket system to its new Microsoft XPS Document Writer (MXDW) driver. For details see MXDW Configuration Settings.

If we suppose that a fictional Ajax Embosser's company defined the BrailleGrade3 translation feature in a way that is parallel to how Microsoft defined the document collation feature, then we can see what the PrintCapabilities and PrintTicket document entries for the feature would look like. Notice that the namespace where the feature is defined must be declared in the <PrintCapabilities … > and <PrintTicket … > start tags.

The PrintCapabilities Document Markup

<psf:PrintCapabilities xmlns:psf="https://schemas.microsoft.com/windows/2003/08/printing/printschemaframework" 
           xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" 
           xmlns:xsd="https://www.w3.org/2001/XMLSchema" 
           xmlns:ajax="https://www.AjaxEmbossers.com/schemas/deluxemodels" version="1">

   <!-- other features omitted --> 
   
   <psf:Feature name="ajax:BrailleGrade3Translation">
        <psf:Property name="psf:SelectionType">
            <psf:Value xsi:type="xsd:QName">psk:PickOne</psf:Value>
        </psf:Property>
        <psf:Property name="psk:DisplayName">
            <psf:Value xsi:type="xsd:string">Braille3 translation</psf:Value>
        </psf:Property>
        <psf:Option name="ajax:Translated" constrained="psk:None">
            <psf:Property name="psk:DisplayName">
                <psf:Value xsi:type="xsd:string">Yes</psf:Value>
            </psf:Property>
        </psf:Option>
        <psf:Option name="ajax:Untranslated" constrained="psk:None">
            <psf:Property name="psk:DisplayName">
                <psf:Value xsi:type="xsd:string">No</psf:Value>
            </psf:Property>
        </psf:Option>
    </psf:Feature>
                   
   <!-- other features omitted --> 
   
</PrintCapabilities>

The PrintTicket Document Markup

<psf:PrintTicket xmlns:psf="https://schemas.microsoft.com/windows/2003/08/printing/printschemaframework" 
           xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" 
           xmlns:xsd="https://www.w3.org/2001/XMLSchema" 
           xmlns:ajax="https://www.AjaxEmbossers.com/schemas/deluxemodels" version="1">
  
  <!-- other features omitted -->
  
  <psf:Feature name="ajax:BrailleGrade3Translation">
    <psf:Option name="ajax:Translated" />
  </psf:Feature>  
    
  <!-- other features omitted -->
  
</PrintTicket>

For more information on writing PrintTicket documents that handle new features see Creating a Device-Specific PrintTicket. For extensive documentation about creating PrintTicket and PrintCapabilities documents, see the PrintCapabilities Schema and Document Construction and PrintTicket Schema and Document Construction sections of the Print Schema documentation.

Overloading and Extending Properties and Methods

Any method of any class that either takes a PrintTicket parameter or returns a PrintTicket, and that you want to use with your extended features system, will have to be replaced by a method that uses WholePrintTicket in place of PrintTicket. Similarly, any properties of type PrintTicket that you want to use will have to be replaced with properties of type WholePrintTicket. The same points apply, mutatis mutandis, to PrintCapabilities and WholePrintCapabilities.

When the class that hosts the method or property is inheritable, you can derive a class and overload the method or property to use WholePrintTicket in place of PrintTicket.

If the hosting class is not inheritable, you will need to extend it the way PrintTicket and PrintCapabilities were extended above: create a class that has the hosting class as a member. Then give the outer class methods and properties with the same names as the corresponding methods that have (or return) PrintTicket or PrintCapabilities parameters. Typically, the outer class should match the functionality of the inner class of the same name, but it will use WholePrintTicket or WholePrintCapabilities parameters instead of PrintTicket or PrintCapabilities parameters. Also, for properties of the inner class that are of type PrintTicket or PrintCapabilities, create a matching property of the same name in the outer class that uses WholePrintTicket or WholePrintCapabilities.

Probably, the most important methods you will need to overload are the two versions of the MergeAndValidatePrintTicket The BrailleEmbosser class (see Derive a New Class by Inheritance above) will need replacements that use WholePrintTicket parameters and that add logic to validate tickets with new features against the schema of the private namespace. You can either overload the existing methods or create new ones named MergeAndValidateWholePrintTicket.

Two methods that return a PrintTicket are ConvertDevModeToPrintTicket and Clone. In .NET Framework there are 15 other methods, not counting overloads, that take a PrintTicket parameter and 19 properties of type PrintTicket. But it is not likely than any given application will use more than a small number of these, so your workload will not be as high as those numbers might suggest. Happily, the only method that returns a PrintCapabilities object is GetPrintCapabilities and there are no properties with type PrintCapabilities.

Expanding Schema-Defined Features

Wholly new features are not the only situation that might require an extension of the Print Schema. It is also possible that a device will offer new, undefined, options for a familiar, defined feature. Since a private namespace must be used for the new undefined options just as it must be used for an entirely new feature, it is probably easier to treat such extended features just as you treat entirely new features (but use the schema-defined names for the feature and those of its options that are already defined): house them in your NewFeaturesPrintTicket and NewFeaturesPrintCapabilities. Discussing all of the details that are needed to implement this kind of schema extension goes beyond the bounds of this article, but note that the concatenation work that must be done by the WholePrintTicket.GetXmlStream and WholePrintTicket.SaveAs methods would have to become somewhat more complicated.

Extending the System.Printing.IndexedProperties Namespace

If you want to take advantage of the APIs in the System.Printing.IndexedProperties namespace, you might need to derive a new class from PrintProperty. You would need to do this if a property you have created for the class you have derived from PrintQueue has a type that is not represented by any of the existing classes in System.Printing.IndexedProperties. For examples of what can be done with he System.Printing.IndexedProperties namespace, see How to: Clone a Printer and How to: Get Print System Object Properties Without Reflection

This is not necessary for our example above, since the only property we added to our BrailleEmbosser class is IsBraile3Enabled, which is Boolean. There is already a System.Printing.IndexedProperties.PrintBooleanProperty class.

See Also

Tasks

How to: Clone a Printer

How to: Get Print System Object Properties Without Reflection

Reference

System.Printing

System.Printing.IndexedProperties

System.Printing.Interop

System.Windows.Xps

System.Windows.Xps.Packaging

System.Windows.Xps.Serialization

GetPrintCapabilities

PackageRelationship

PrintCapabilities

PrintQueue

PrintSystemObject

PrintTicket

MXDW Configuration Settings

Concepts

XML Processing Options in the .NET Framework

Documents in WPF

Printing Overview

Other Resources

Print Schema

Print Schema Framework

Creating a Device-Specific PrintTicket

Print Schema-Related Technologies

PrintTicket Schema and Document Construction

PrintTicket Example

PrintCapabilities Document Example

PrintCapabilities Schema and Document Construction

Print Schema Public Keywords

Microsoft XPS Document Writer