Monday, 22 October 2012

Listing Font Names in Windows 8 C# XAML Apps

I thought this would be a two line job, but as often in Windows 8, things aren't always as you'd expect. All I wanted to do was list font names for a combo box picker, but found you need to use DirectX DirectWrite to get the font names.

There's an example of doing this in an HTML/JS app using a C++ interop here:

http://code.msdn.microsoft.com/windowsapps/DirectWrite-font-60e53e0b

I can't really beleive we need to go to such lengths to do something so simple, but luckily SharpDX comes to the rescue (again). It's still a bit convoluted having to interrogate the DirectWrite font family collections, but loads easier than writing a C++ interop!

Here's a helper class I wrote to get font names:


using SharpDX.DirectWrite;
using System.Collections.Generic;
using System.Linq;

namespace WebberCross.Helpers
{
    public class FontHelper
    {
        public static IEnumerable<string> GetFontNames()
        {
            var fonts = new List<string>();

            // DirectWrite factory
            var factory = new Factory();

            // Get font collections
            var fc = factory.GetSystemFontCollection(false);

            for (int i = 0; i < fc.FontFamilyCount; i++)
            {
                // Get font family and add first name
                var ff = fc.GetFontFamily(i);

                var name = ff.FamilyNames.GetString(0);
                fonts.Add(name);
            }

            // Always dispose DirectX objects
            factory.Dispose();

            return fonts.OrderBy(f => f);
        }
    }
}

Tuesday, 9 October 2012

Using a ManualResetEvent To Stop A Console Application From Terminating


This is a quick example of how to use a ManualResetEvent to stop a console application from terminating whilst an event driven (or callback driven) asynchronous process is busy.




Basically a ManualResetEvent is waited on at the end of the main method until it is signalled to complete by one of the events:

using System;
using System.Threading;

namespace ConsoleApplicationWait
{
  class Program
  {
    static ManualResetEvent _mre = new ManualResetEvent(false);
    static EventSource _src = new EventSource();

    static void Main(string[] args)
    {
      _src.NewNumber += _src_NewNumber;
      _src.Finished += _src_Finished;

      // Starting events
      _src.Start();

      // Block main thread until signalled to continue
      Console.WriteLine("Reached the end of main method and waiting for signal...");
      _mre.WaitOne();

      Console.WriteLine("Signal received, press enter to exit...");
      Console.ReadLine();
    }

    static void _src_Finished(object sender, EventArgs e)
    {
      Console.WriteLine("Finished event received, signalling all done");

      // Signal wait handle to continue
      _mre.Set();
    }

    static void _src_NewNumber(object sender, NumberEventArgs e)
    {
      Console.WriteLine(e.Number);
    }
  }

  /// <summary>
  /// Simple number eventargs
  /// </summary>
  public class NumberEventArgs : EventArgs
  {
    public int Number { get; set; }

    public NumberEventArgs(int number)
    {
      this.Number = number;
    }
  }

  /// <summary>
  /// Class to simulate something which generates a number of events
  /// </summary>
  public class EventSource
  {
    public event EventHandler<NumberEventArgs> NewNumber;
    public event EventHandler Finished;

    public void Start()
    {
      Thread t = new Thread(new ThreadStart(() =>
        {
          for (int i = 0; i < 10; i++)
          {
            if (this.NewNumber != null)
              this.NewNumber(this, new NumberEventArgs(i));

            // 1s delays so we can see what's going on
            Thread.Sleep(1000);
          }

          if (this.Finished != null)
            this.Finished(this, new EventArgs());
        }));

      t.Start();
    }
  }
}

Thursday, 4 October 2012

Windows 8 ItemTapCommand Attached Property

This attached property picks up touch tap events from FrameworkElements and triggers an attached command. This is useful for controls like GridViews where you might click an item or tap it to perform an action.


public class ItemTapCommand
{
  public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(ItemTapCommand), new PropertyMetadata(null, CommandPropertyChanged));

  public static void SetCommand(DependencyObject attached, ICommand value)
  {
    attached.SetValue(CommandProperty, value);
  }

  public static ICommand GetCommand(DependencyObject attached)
  {
    return (ICommand)attached.GetValue(CommandProperty);
  }

  private static void CommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
    // Attach tap handler
    (d as FrameworkElement).Tapped += ItemTapCommand_Tapped;
  }
       
  private static void ItemTapCommand_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
  {
    // Get command
    ICommand command = GetCommand(sender as DependencyObject);

    // Execute command
    command.Execute(null);
  }
}

This example shows it attached to a GridView item (grid) and using a command from the view model via the context of the GridView:

<GridView ItemsSource="{Binding Items}"
  SelectedItem="{Binding SelectedItem, Mode=TwoWay}" SelectionMode="Single">
  <GridView.ItemTemplate>
    <DataTemplate>
      <Grid Width="133" Height="200"
cmd:ItemTapCommand.Command="{Binding ElementName=posterGrid, Path=DataContext.EditCommand}">


Saturday, 15 September 2012

Exporting an image from a DirectX 2D Image in Windows 8 C#/XAML Using SharpDX - PART 2


In my previous article I talked about how to save and image created by and Effect. I’ve been doing more work on my own project and worked out how to render a 2D drawing and export it.
The trick is to re-draw the image onto a bitmap.
If you create a render method like this one which draws a gradient:

private void Render(DeviceContext context2D)
{
  context2D.BeginDraw();

  var size = context2D.PixelSize;

  // Add brush fill
  var stops = new GradientStopCollection(context2D, new GradientStop[] {
  new GradientStop() { Color = Colors.Green, Position = 0 },
  new GradientStop() { Color = Colors.Yellow, Position = 1f }});

  var brushProps = new LinearGradientBrushProperties();
          brushProps.StartPoint = new DrawingPointF(size.Width / 2, 0);
            brushProps.EndPoint = new DrawingPointF(size.Width / 2, size.Height);

  var brush = new LinearGradientBrush(context2D, brushProps, stops);
  context2D.FillRectangle(new RectangleF(0, 0, (float)size.Width, (float)size.Height), brush);

  context2D.EndDraw();
}

It  can be used by the SurfaceImageSource’s render event and then reused for the export. To do the save, a clean 2D Device and DeviceContext needs creating from the default 3D device, then an image is created and the drawing rendered onto it:

public async void Save()
{
  // Get 3D device for creating 2D device
  var device3D =
  new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware,
                    SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport);

  // Get DXGI device
  var dxgiDevice2 = device3D.QueryInterface<SharpDX.DXGI.Device2>();           
 
  // Create new 2D device
  var device2D = new Device(dxgiDevice2);
  var context2D = new DeviceContext(device2D, DeviceContextOptions.None);

  // Create image
  SharpDX.Direct2D1.PixelFormat format = new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied);
  SharpDX.Direct2D1.BitmapProperties1 props = new BitmapProperties1(format,
                Windows.Graphics.Display.DisplayProperties.LogicalDpi,
                Windows.Graphics.Display.DisplayProperties.LogicalDpi,
                BitmapOptions.Target | BitmapOptions.CannotDraw);
  SharpDX.Direct2D1.Bitmap1 saveImage = new Bitmap1(context2D,   this._deviceManager.ContextDirect2D.PixelSize, props);
  context2D.Target = saveImage;

  // Render
  this.Render(context2D);

Now we have finally caught our drawing and we can export it in the same way as the last article:

// Launch file picker
Windows.Storage.Pickers.FileSavePicker picker = new Windows.Storage.Pickers.FileSavePicker();
picker.FileTypeChoices.Add("Png", new List<string>() { ".png" });
var file = await picker.PickSaveFileAsync();
if (file == null)
  return;

// Create imaging factory
var factory = new ImagingFactory();

// Get stream
var fStream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);          
MemoryStream ms = new MemoryStream(100000);
ms.Position = 0;

// Create a WIC outputstream
WICStream stream = new WICStream(factory, ms);

var size = context2D.PixelSize;

// Initialize a Jpeg encoder with this stream
var wicBitmapEncoder = new SharpDX.WIC.PngBitmapEncoder(factory, BitmapEncoderGuids.Png);
wicBitmapEncoder.Initialize(stream);

// Create a Frame encoder
var wicFrameEncoder = new BitmapFrameEncode(wicBitmapEncoder);
wicFrameEncoder.Initialize();

// Create image encoder
ImageEncoder wicImageEncoder;
SharpDX.WIC.ImagingFactory2 factory2 = new ImagingFactory2();
factory2.CreateImageEncoder(device2D, out wicImageEncoder);

var imgParams = new ImageParameters();
imgParams.PixelFormat = format;
imgParams.PixelHeight = (int)size.Height;
imgParams.PixelWidth = (int)size.Width;
wicImageEncoder.WriteFrame(saveImage, wicFrameEncoder, ref imgParams);

// Commit changes
wicFrameEncoder.Commit();
wicBitmapEncoder.Commit();

byte[] buffer = new byte[ms.Length];
ms.Position = 0;
await ms.ReadAsync(buffer, 0, (int)ms.Length);
var opStream = fStream.AsStreamForWrite();
await opStream.WriteAsync(buffer, 0, buffer.Length);
await opStream.FlushAsync();

// Dispose
wicFrameEncoder.Dispose();
wicBitmapEncoder.Dispose();
stream.Dispose();
ms.Dispose();
opStream.Dispose();
factory.Dispose();

Well, I have a few more issues of my own to solve, but this is all the tough stuff done!

Wednesday, 12 September 2012

Exporting an image from a DirectX 2D Image in Windows 8 C#/XAML Using SharpDX

PART 2

I’m working on a Windows 8 app which has a drawing element to it. The original WP7 app in Silverlight was fine because a simple drawing rendered in XAML was captured using WritableBitmap.Render and written to a file stream. This feature is missing from the Windows 8 API, so it’s impossible to write a pure C#/XAML app which can export a user created image. To get round this it’s possible to use DirectX/XAML/C++ to create a XAML UI which can draw DirectX images.

DirectX/XAML/C++ offers a number of XAML containers which interface with DirectX and have different behaviours:



I wanted to use a SurfaceImageSource, so I could have my DirectX image in line with other XAML controls and containers.

The big problem is that I don’t want to write a whole app in C++, it would take me a lot longer than C# and it seemed like a sledge hammer to crack a nut using full C++/DirectX for a simple application.

So after much research and stress about what to do, I found SharpDX and thought all my prayers had been answered! SharpDX is a full DirectX to C# interop library which allows DirectX to be brought into C#/XAML apps in the same way as C++/XAML apps.


The major problem was how to save the image you’ve drawn out of the DirectX image? There are a small number of examples of how to do it in C++, so after a lot of cross referencing the SharpDX source and tips from Alexandre Mutel on interfacing with a WICStream, I managed to get it working.

This save method was tested inside the EffectRenderer in the SharpDX lighting effect sample. This is the whole code so you don’t need to paste it back together in sections:

public async void Save()
{
    // Launch file picker
    Windows.Storage.Pickers.FileSavePicker picker = new Windows.Storage.Pickers.FileSavePicker();
    picker.FileTypeChoices.Add("PNG", new List<string>() { ".png" });
    var file = await picker.PickSaveFileAsync();
    if (file == null)
        return;

    // Get stream
    var fStream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);

    var factory = new ImagingFactory();

    MemoryStream ms = new MemoryStream(100000);
    ms.Position = 0;

    // Create a WIC outputstream
    WICStream stream = new WICStream(factory, ms);

    var size = this._deviceManager.ContextDirect2D.PixelSize;
    var format = new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, AlphaMode.Premultiplied);

    // Initialize a Png encoder with this stream
    var wicBitmapEncoder = new SharpDX.WIC.PngBitmapEncoder(factory, BitmapEncoderGuids.Png);
    wicBitmapEncoder.Initialize(stream);

    // Create a Frame encoder
    var wicFrameEncoder = new BitmapFrameEncode(wicBitmapEncoder);
    wicFrameEncoder.Initialize();

    // Create image encoder
    ImageEncoder wicImageEncoder;
    SharpDX.WIC.ImagingFactory2 factory2 = new ImagingFactory2();
    factory2.CreateImageEncoder(this._deviceManager.DeviceDirect2D, out wicImageEncoder);

    var imgParams = new ImageParameters();
    imgParams.PixelFormat = format;
    imgParams.PixelHeight = (int)size.Height;
    imgParams.PixelWidth = (int)size.Width;
    wicImageEncoder.WriteFrame(_effectGraph.Output, wicFrameEncoder, ref imgParams);

    // Commit changes
    wicFrameEncoder.Commit();
    wicBitmapEncoder.Commit();

    byte[] buffer = new byte[ms.Length];
    ms.Position = 0;
    await ms.ReadAsync(buffer, 0, (int)ms.Length);
    var opStream = fStream.AsStreamForWrite();
    await opStream.WriteAsync(buffer, 0, buffer.Length);
    await opStream.FlushAsync();

    // Dispose
    wicFrameEncoder.Dispose();
    wicBitmapEncoder.Dispose();
    stream.Dispose();
    ms.Dispose();
    opStream.Dispose();    
    factory.Dispose();
}

The first section gets a file stream from the user to write the data to once it’s been extracted from the image, then creates an intermediary MemoryStream for the WICStream to interface with (Alexandre pointed out that the Win8 RandomAccessStream will not interface with a WICStream since it needs to perform seek operations) and finally the WICStream itself which WIC will use to write the image to.

The second section creates a Bitmap Encoder, Frame Encoder and Image Encoder and writes the image frame into the stream.

The final section and the bit which caused me a lot of problems, is getting the data from the stream. The encoders all need committing in order, but in many C++ examples the WICStream is also committed which should flush the stream to it’s destination, however it was throwing an exception:

An exception of type 'SharpDX.SharpDXException' occurred in SharpDX.DLL but was not handled in user code

Additional information: HRESULT: [0x88982F50], Module: [Unknown], ApiCode: [Unknown/Unknown], Message: The component cannot be found.

If there is a handler for this exception, the program may be safely continued.

This isn’t particularly helpful, but I was advised that the WIC stream doesn’t need flushing as the underlying stream should take care of this. At this point I could see the memory stream had a size, but when I wrote it to a buffer it was coming out all zeros. This was a simple mistake – the memory stream just needs setting back to the start and it all started magically working!

All I need to do now is work out how to use DirectX to draw my picture! I hope this helps some other people as it’s been causing me a massive headache for a number of days!

Friday, 17 August 2012

Obelisk Windows 8 & WP7 MVVM Persistence Library V2.2 Release

I've just finished the Obelisk V2.2 release. It's now got support for Windows 8 persistence as well as WP7 persistence. There is a basic MVVM pattern example and an MVVM Light example for WP7 and Windows 8 The MSI only contains source for WP7 because I can't create an MSI in VS2012 yet, so you need to download the source to get the samples:

http://obelisk.codeplex.com/

Tuesday, 7 August 2012

Windows 8 Audio Player Demo

Overview

I need to include a podcast player in the app I'm writing, so I decided to write a prototype app to demo the Windows 8 audio capabilities

Source here: https://bitbucket.org/webbercross/win8audioplayer/


Features

I wanted to include the following:

  • Background capabilities
  • Live tile glyph updates
  • A custom re-templatable control
  • Hardware interaction
  • Fully working demo with all required tasks

Background Audio

I've previously use the Background Audio Agent in WP7 and was expecting something similar. There's no direct equivalent but the MediaElement is Windows 8 provides new features different to Silverlight. The new MediaElement has an 'AudioCategory' attribute which can be set to 'BackgroundCapableMedia' to allow it to continue playing while the page is not active or when the app is suspended, but not closed.

<MediaElement x:Name="mediaElement" AudioCategory="BackgroundCapableMedia" AutoPlay="False"/>

The manifest needs modifying to have a Background declaration with 'Audio' and 'Control channel' properties:


Additionally, a wide tile must be used.

Live Tile Glyph Updates

I wasn't sure at first if this was done automatically by the task, but it's not, it needs doing manually, so I wrote a helper class to do it:

public enum Glyphs
{
  none,
  activity,
  alert,
  available,
  away,
  busy,
  newMessage,
  paused,
  playing,
  unavailable,
  error,
  attention,
}

public class BadgeHelper
{
  public static void UpdateBadge(Glyphs glyph)
  {
    // Get badge xml content
    var content = BadgeUpdateManager.GetTemplateContent(Windows.UI.Notifications.BadgeTemplateType.BadgeGlyph);
    var element = content.GetElementsByTagName("badge")[0];

    // Set new glyph value
    element.Attributes[0].NodeValue = glyph.ToString();

    // Update badge
    var notification = new BadgeNotification(content);
    BadgeUpdateManager.CreateBadgeUpdaterForApplication().Update(notification);
  }
}

Normal tile:


Tile with play glyph:



Custom Template

This is the same as Silverlight and WPF, I put in some visual states for play and paused mode. The template is in the default Templates\Generic.xaml location.

Hardware Interaction

The MediaControl object has a number of events which can be subscribed to.

The Demo

[Edit] The demo is now finished, enjoy!