Wednesday, January 29, 2014

How to use DoubleAnimation in Windows Store Apps with C# without using XAML


I seem to find myself looking this up every time I go to create an animation, and since most of the example online use XAML, I wanted to write an easy to follow example to reference.
There is a great article on MSDN about using Animations in .NET 4.5 and it does provide a pure C# example.  However, there is a subtle difference in how you attach dependency properties for Windows Store / RT apps. 
http://msdn.microsoft.com/en-us/library/ms752312(v=vs.110).aspx

1st – you don’t need an object name when setting the Animation target.  You just need to pass the instance of the target.
.NET 4.5 –> StoryBoard.SetTarget(myDoubleAnimation, myTarget.Name);
Win8 Store –> StoryBoard.SetTarget(myDoubleAnimation, myTarget);
2nd – you reference the target animation property by name (ie a string) rather than creating a Property Path.  Basically they’ve just streamlined the process a bit.
Now onto the code.  I’ve placed everything into a single method with lazy loading, which isn’t likely how I would do it in production code, but it gets the job done.  As well, it shows how to add multiple DoubleAnimations to a single storyboard.  It’s straight forward but it seems to be a common question.  Note – we aren’t able to set multiple targets for one Animation.
Finally, the animation itself is a fun one to use, especially against a white background as objects appear to “flash” and then return to their original state.
I typically use this on custom UserControls but any UI object should work fine.
Here it is:
Storyboard storyPop;
DoubleAnimation dbAniX, dbAniY, dbAniFade;
public void FlashPop ()
{
    if (dbAniX == null)
    {
        ScaleTransform sTrans = new ScaleTransform() { ScaleX = 1.0, ScaleY = 1.0, CenterX = this.ActualWidth / 2, CenterY = this.ActualHeight / 2 };
        this.RenderTransform = sTrans;
 
        dbAniX = new DoubleAnimation() { From = 1.0, To = 2.0, Duration = TimeSpan.FromMilliseconds(100), AutoReverse = true };
        dbAniY = new DoubleAnimation() { From = 1.0, To = 2.0, Duration = TimeSpan.FromMilliseconds(100), AutoReverse = true };
        dbAniFade = new DoubleAnimation() { From = 1.0, To = 0.0, Duration = TimeSpan.FromMilliseconds(100), AutoReverse = true };
 
        Storyboard.SetTarget(dbAniX, sTrans);
        Storyboard.SetTarget(dbAniY, sTrans);
        Storyboard.SetTarget(dbAniFade, this);
 
        Storyboard.SetTargetProperty(dbAniY, "ScaleY");
        Storyboard.SetTargetProperty(dbAniX, "ScaleX");
        Storyboard.SetTargetProperty(dbAniFade, "Opacity");
    }
    
    if(storyPop == null)
    {
        storyPop = new Storyboard();
        storyPop.Children.Add(dbAniX);
        storyPop.Children.Add(dbAniY);
        storyPop.Children.Add(dbAniFade);
    }
 
    storyPop.Begin();
}

Tuesday, January 28, 2014

How to implement Semantic Zoom without XAML for Windows 8 / RT in C#


I was experimenting with the Semantic Zoom control and wanted to see how it behaved with controls other than a GridView or ListView.  Here’s a quick and dirty example of how to set it up purely in C#.

mainGrid = new Grid();
 
SemanticZoom semZoom = new SemanticZoom();
 
Border brdIn = new Border();
brdIn.Background = CreateSolidColorBrush(Colors.Red);
brdIn.Height = brdIn.Width = 400;
 
Border brdOut = new Border();
brdOut.Background = CreateSolidColorBrush(Colors.Blue);
brdOut.Height = brdOut.Width = 400;
 
var gr1 = new GridView();
gr1.Header = brdIn;
 
var gr2 = new GridView();
gr2.Header = brdOut;
 
semZoom.ZoomedOutView = gr1;
semZoom.ZoomedInView = gr2;
 
mainGrid.Add(semZoom);

Monday, January 6, 2014

Getting Started with NAudio and WinRT C# (Windows 8 Store)


I’ve recently been experimenting with the Audio APIs available for Windows Store apps and I discovered there’s an early release of NAudio working for Windows 8 Store apps.
I wouldn’t recommend using it in a commercial app without thorough testing but its definitely worth taking a look as its sure to be updated in the coming months. As the time of writing the current release is 1.7.0 beta 01.

1. Get the NAudio nuget Package

https://www.nuget.org/packages/NAudio
If you’re not experienced with nuget you can open the package manger prompt by navigating to:
TOOLS –> Library Package Manager –> Package Manager Console in Visual Studio 2012/2013
And then type in “Install-Package NAudio” (without the quotes of course).  If you have multiple projects in your solution make sure you have the correct project selected in the Default Project dropdown.

2. Read Mark Heath’s excellent post on NAudio

http://mark-dot-net.blogspot.ca/2009/10/playback-of-sine-wave-in-naudio.html
This post goes all the way back to 2009 but we can use most of his example code verbatim.

3. Copy/Create Mark’s WaveProvider32 and SineWaveProvider32 classes

Both of this classes will work without modification.  You’ll just need to add the NAudio using:
using NAudio.Wave;

4. Create a Win8 WasapiOutRT

You’ll need to update Mark’s example to actually make some noise.
Now we’ll need an instance of WasapiOutRT instead WaveOut.  Make this a member variable not a local variable.
NAudio.Win8.Wave.WaveOutputs.WasapiOutRT waveOut;
And the final important notes, to use  the “StartStopSineWave” mthod you’ll need to mark it as async and await the Init call.  Otherwise you’ll get silence and no obvious error messages.  My edits look like this:
private async void StartStopSineWave()
{
    if (waveOut == null)
    {
        var sineWaveProvider = new SineWaveProvider32();
        sineWaveProvider.SetWaveFormat(16000, 1); // 16kHz mono
        sineWaveProvider.Frequency = 440;
        sineWaveProvider.Amplitude = 0.8f;
        waveOut = new NAudio.Win8.Wave.WaveOutputs.WasapiOutRT(NAudio.CoreAudioApi.AudioClientShareMode.Shared, 100);
        await waveOut.Init(sineWaveProvider);
        waveOut.Play();
    }
    else
    {
        waveOut.Stop();
        waveOut.Dispose();
        waveOut = null;
    }
}   


One other quick note.  Moving forward, if you decide to change the WaveProvider32 class to use 2 channels rather than 1 you’ll want to edit the sample rate in the Read method in SineWaveProvider32:

int sampleRate = WaveFormat.SampleRate * WaveFormat.Channels;



For more information you’re best bet is the NAudio dissusions on CodePlex:

http://naudio.codeplex.com/discussions



My next goal is to try capturing audio.  Happy Coding!