Skip to content

Instantly share code, notes, and snippets.

@ichengzi
Last active September 19, 2015 12:56
Show Gist options
  • Save ichengzi/d5c443b04cd7d9c87b15 to your computer and use it in GitHub Desktop.
Save ichengzi/d5c443b04cd7d9c87b15 to your computer and use it in GitHub Desktop.
Xaml Console Printer
namespace XamlConsolePrinter
{
using System.Printing;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Schedulers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Xps;
internal class Program
{
private class PrintControl : UserControl
{
public PrintControl()
{
var textBlock = new TextBlock {Text = "Hi there!"};
Content = textBlock;
}
}
private static void Main(string[] args)
{
var scheduler = new StaTaskScheduler(numberOfThreads: 1);
var task = Task.Factory
.StartNew(() =>
{
var printQueue = LocalPrintServer.GetDefaultPrintQueue();
var ticket = new PrintTicket
{
OutputColor = OutputColor.Color,
PageMediaType = PageMediaType.Plain,
PageOrientation = PageOrientation.Landscape,
PageMediaSize = new PageMediaSize(PageMediaSizeName.Roll04Inch),
PageBorderless = PageBorderless.Borderless
};
var result = printQueue.MergeAndValidatePrintTicket(printQueue.UserPrintTicket, ticket);
var pageMediaSize = result.ValidatedPrintTicket.PageMediaSize;
if (!pageMediaSize.Height.HasValue || !pageMediaSize.Width.HasValue)
return;
// XAML control to print
var visual = new PrintControl();
visual.Arrange(new Rect(new Size(pageMediaSize.Width.Value, pageMediaSize.Height.Value)));
var documentWriter = PrintQueue.CreateXpsDocumentWriter(printQueue);
var visualsToXpsDocument = (VisualsToXpsDocument) documentWriter.CreateVisualsCollator();
if (visualsToXpsDocument == null) return;
visualsToXpsDocument.Write(visual);
visualsToXpsDocument.EndBatchWrite();
}, CancellationToken.None, TaskCreationOptions.None, scheduler);
task.Wait();
}
}
}
//--------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: StaTaskScheduler.cs
//
//--------------------------------------------------------------------------
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace System.Threading.Tasks.Schedulers
{
/// <summary>Provides a scheduler that uses STA threads.</summary>
public sealed class StaTaskScheduler : TaskScheduler, IDisposable
{
/// <summary>Stores the queued tasks to be executed by our pool of STA threads.</summary>
private BlockingCollection<Task> _tasks;
/// <summary>The STA threads used by the scheduler.</summary>
private readonly List<Thread> _threads;
/// <summary>Initializes a new instance of the StaTaskScheduler class with the specified concurrency level.</summary>
/// <param name="numberOfThreads">The number of threads that should be created and used by this scheduler.</param>
public StaTaskScheduler(int numberOfThreads)
{
// Validate arguments
if (numberOfThreads < 1) throw new ArgumentOutOfRangeException("numberOfThreads");
// Initialize the tasks collection
_tasks = new BlockingCollection<Task>();
// Create the threads to be used by this scheduler
_threads = Enumerable.Range(0, numberOfThreads).Select(i =>
{
var thread = new Thread(() =>
{
// Continually get the next task and try to execute it.
// This will continue until the scheduler is disposed and no more tasks remain.
foreach (var t in _tasks.GetConsumingEnumerable())
{
TryExecuteTask(t);
}
}) {IsBackground = true};
thread.SetApartmentState(ApartmentState.STA);
return thread;
}).ToList();
// Start all of the threads
_threads.ForEach(t => t.Start());
}
/// <summary>Queues a Task to be executed by this scheduler.</summary>
/// <param name="task">The task to be executed.</param>
protected override void QueueTask(Task task)
{
// Push it into the blocking collection of tasks
_tasks.Add(task);
}
/// <summary>Provides a list of the scheduled tasks for the debugger to consume.</summary>
/// <returns>An enumerable of all tasks currently scheduled.</returns>
protected override IEnumerable<Task> GetScheduledTasks()
{
// Serialize the contents of the blocking collection of tasks for the debugger
return _tasks.ToArray();
}
/// <summary>Determines whether a Task may be inlined.</summary>
/// <param name="task">The task to be executed.</param>
/// <param name="taskWasPreviouslyQueued">Whether the task was previously queued.</param>
/// <returns>true if the task was successfully inlined; otherwise, false.</returns>
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// Try to inline if the current thread is STA
return
Thread.CurrentThread.GetApartmentState() == ApartmentState.STA &&
TryExecuteTask(task);
}
/// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
public override int MaximumConcurrencyLevel
{
get { return _threads.Count; }
}
/// <summary>
/// Cleans up the scheduler by indicating that no more tasks will be queued.
/// This method blocks until all threads successfully shutdown.
/// </summary>
public void Dispose()
{
if (_tasks == null) return;
// Indicate that no new tasks will be coming in
_tasks.CompleteAdding();
// Wait for all threads to finish processing tasks
foreach (var thread in _threads) thread.Join();
// Cleanup
_tasks.Dispose();
_tasks = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment