Silverlight 2.0: Creating a basic animation through code

by Andrej Tozon 10. March 2008 08:52

In my previous Silverlight post, I mentioned Silverlight 2.0 API now allows creating animations through code. While this wasn't possible with Silverlight 1.1 Alpha [you would have to create of piece of Xaml, declaring a storyboard with all animations markup, then load it into a Storyboard object by using XamlReader.Load() method], Silverlight 2.0 now makes it pretty easy.

The following animation code will create very basic fade out effect for given element, animating the Opacity property from 1 to 0 in one second:

private DoubleAnimation CreateFadeOutAnimation(string elementName)
{
    DoubleAnimation animation = new DoubleAnimation();
    Storyboard.SetTargetName(animation, elementName);
    Storyboard.SetTargetProperty(animation, "Opacity");
    animation.To = 0;
    animation.Duration = new Duration(TimeSpan.FromSeconds(1));
    return animation;
}
To start this animation, you'll have to add it to a new storyboard first:
Storyboard sb = new Storyboard();
sb.Children.Add(CreateFadeOutAnimation("myElement"));
sb.Duration = new Duration(TimeSpan.FromSeconds(1));
sb.Completed += new EventHandler(sb_Completed);
LayoutRoot.Resources.Add(sb);
sb.Begin();

The "myElement" above is the name of an visual element with this name, which has to exist in the context of the storyboard for it see it. Storyboard is added to the LayoutRoot's resources [LayoutRoot is the name of a default root Grid in Silverlight]. Instead of passing just a name of an element, you could as well pass in the actual element you're animating.

Note the Completed event hookup up there. This is because we want to stop and remove the animation from the resources when animation is done to clean things up a bit. Here's the handler:

void sb_Completed(object sender, EventArgs e)
{
Storyboard sb = (Storyboard)sender; sb.Stop(); this.Resources.Remove(sb); }

That's it. Of course you can add as many animations to the storyboard as you want - animating different elements at the same time, adding different animations, etc... In further posts we might add some more complexity to this basic sample.

Tags:

Silverlight | Development

How well do you know your Culture?

by Andrej Tozon 28. February 2008 14:33

When doing code reviews, I often stumble upon a piece of code with some culture-specific information hard-coded in it. One example of this being month names:

string[] months =
   
{
        "January",
       
"February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
       
"October",
        "November",
        "December"
   
};

This is all fine if your application is intended for English spoken users and all that, but hey - why try and duplicate something, what's already been done for you? CultureInfo class has all the information you need:

string[] months = CultureInfo.CurrentCulture.DateTimeFormat.MonthNames;

And if you need the name of the months in some other supported language, all you have to do is ask [this one's for Slovenia):

string[] months = CultureInfo.GetCultureInfo("sl-SI").DateTimeFormat.MonthNames;

Then again, if all you need is month names in shortened form, the class can also help:

string[] months = CultureInfo.CurrentCulture.DateTimeFormat.AbbreviatedMonthNames;

If you're after just one specific month name, it will bi provided for you [the following line will get you February - obviously]:

string month = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(2);

And so on... The same pattern applies for day names, etc. If there is anything specific that you would want to know about a certain culture, CultureInfo class will give you all the information you need. Given these possibilities, one can even create a custom culture using the CultureAndRegionInfoBuilder class. There's quite a few examples of where this would come in useful.

One thing to note though: The MonthNames properties described above will return you the string array of 13 items; although majority of cultures have 12 months in a year, a few apparently have 13, so be aware of that when using these properties. If month names list is intended for a data source that can be bound to, you may want to return the actual number of months. The following method will return the actual number of months in a given year:

int mothCount = CultureInfo.CurrentCulture.DateTimeFormat.Calendar.GetMonthsInYear(DateTime.Today.Year);

The other way would be just skipping the empty months. There are again, several ways to do this - today, the weapon of choice is fashionable - Linq [or rather - its extensions], although it's most likely not the fastest way of doing it:

string[] cultureMonths = CultureInfo.CurrentCulture.DateTimeFormat.MonthNames;
string[] months = cultureMonths.TakeWhile<string>(month => month.Length > 0).ToArray<string>();

The TakeWhile method will return only those items, for which lambda expression would return true. Also not that I could as easy replace the ToArray<string>() method at the end with ToList<string>() and return a generic list of strings:

List<string> months = cultureMonths.TakeWhile<string>(month => month.Length > 0).ToList<string>();

... but since this is most likely a read-only list, it doesn't really matter.

Tags:

Development

Make your application speak

by Andrej Tozon 23. February 2008 23:54

.NET Framework 2.0 simplified the way of playing audio files from desktop applications. .NET Framework 3.0 takes this one step further by introducing the speech API, residing in the System.Speech namespace (it's basically a wrapper around Microsoft SAPI and is packed in System.Speech.Dll).

Using the SpeechSynthesizer class you can make your computer actually speak the text you feed to it:

SpeechSynthesizer synth = new SpeechSynthesizer();
synth.Speak("Hello world!");

If you don't want to stop your application from blocking the execution while speaking, this is there's the asynchronous equivalent to this method:

SpeechSynthesizer synth = new SpeechSynthesizer();
synth.SpeakAsync("Hello universe!");

The class provides a lot of ways of influencing the sound, like changing the rate, volume, providing hints on pronunciation, including existing sounds and changing the voice. Windows Vista comes with the preinstalled voice called Microsoft Anna, while Microsoft Sam should be available on Windows XP.

OK, so I thought I would update my You've got mail application sample by including some spoken text when new mail "arrives". This is the code I used:

PromptBuilder builder = new PromptBuilder();
builder.AppendAudio(new Uri(@"file://\windows\media\windows notify.wav"));
builder.AppendBreak(PromptBreak.Small);
builder.AppendText("You've got mail.");
builder.AppendBreak(PromptBreak.Small);
builder.AppendText("I think it's from your... wife.");

SpeechSynthesizer synth = new SpeechSynthesizer();
synth.SpeakAsync(builder);

And this is the extended You've got mail sample project for download.

Enjoy. A couple of notes though: The speech API does not require you to build a WPF to use it. You can also use it from Windows Forms or a Console application, just as long as you're targeting .NET FX 3.0. And don't forget to reference the System.Speech.Dll.

You've got mail

Tags:

Windows Vista | WPF | Development

Paste as Xaml Visual Studio Add-In

by Andrej Tozon 20. February 2008 10:26

Common Windows Presentation Foundation controls don't necessarily provide an intuitive path for upgrading from their Windows Forms equivalents. Take, for example, the RichTextBox control - there is no Rtf property for setting and getting RTF formatted text in WPF's RichTextBox. You can however, still load the RTF text into RichTextBox, using this method (loading RTF text from an embedded resource called MyRtfText):

ASCIIEncoding encoding = new ASCIIEncoding();
byte[] bytes = encoding.GetBytes(Properties.Resources.MyRtfText);

using (MemoryStream s = new MemoryStream(bytes))
{
   
TextRange range = new TextRange(rtfBox.Document.ContentStart, rtfBox.Document.ContentEnd);
   
range.Load(s, DataFormats.Rtf);
}

But how about creating a couple of text lines that would fit right into WPF's RichTextBox? RichTextBox exposes the Document property, which would accept a FlowDocument - and that's a native WPF content element, persisted in Xaml format. If you need to insert a piece of document into RichTextBox at design time, you'll have to know some Xaml to to it. Having to convert some existing text from RTF or other rich text format (pasting from Word seems like a good idea) requires a converter...

Luckily, such a converter is already built in WPF - it's the RichTextBox itself! The following snippet will stuff the text from the clipboard (text format doesn't matter, as long it's text) into the RichTextBox and get it out as a FlowDocument:

RichTextBox box = new RichTextBox();
box.Paste();

string text;
TextRange range = new TextRange(box.Document.ContentStart, box.Document.ContentEnd);

using (MemoryStream stream = new MemoryStream())
{
   
range.Save(TextDataFormat.Xaml.ToString());
   
stream.Seek(0, SeekOrigin.Begin);
   
using (StreamReader reader = new StreamReader(stream))
   
{
        text = reader.ReadToEnd();
   
}
}

And this is the core of this very simple Visual Studio 2008 Add-In that I've created - it will allow you to paste any text from the clipboard into Visual Studio as XAML.

Installing the Add-In is as easy as copying a DLL, included in the zip file [see link below], into *\My Documents\Visual Studio 2008\Addins folder and (re)start Visual Studio 2008. You'll find the new command under Tools menu.

image 

Download the Add-In. Full Add-In source code will follow...

On a side note... WPF future looks bright: performance and VS Designer improvements, new setup framework, new controls (DataGrid, Ribbon, Calendar, ...) See this ScottGu's post for more details.

Tags:

WPF | Windows Forms | Development

You've got mail: Windows Forms &amp; WPF interop

by Andrej Tozon 10. February 2008 21:44

One of my favorite samples when talking about WPF is showing a rotating 3D letter 'e' in a Windows Forms application. You know, something like those "you've got mail" computer messages, seen in many Hollywood movies. Windows Forms/WPF interoperability features make this kind of stunt very easy to pull off and this is the recipe to make in happen in 15 minutes...

First, you'll have to come up with some kind of 3D element, which you can import in WPF. I used electric rain's ZAM 3D tool, which has the ability to export 3D elements directly to XAML, which can be later picked up and additionally arranged with  Expression Blend, for example. It actually took me just a couple of minutes to create a 3D letter 'e' and import the scene into Blend.

blendmail1

Rotating the 3D element was done by animating ViewPort's camera by setting 5 progressive key frames of its Rotate Transform property.

image

We need to make the element reusable, so we'll transform it to a user control. Expression Blend 2 (currently still in CTP version) fortunately makes this task very easy by exposing the "Make Control" task (Tools | Make Control...)

OK, half done... We now have a user control with rotating 3D element and a WPF Window, simply displaying it.

The next step is adding a new Windows Form to the project. Save the project in Blend, switch over to Visual Studio (2008) and add a new Form. Visual Studio will make sure all necessary interop assemblies will be added to the project in this process.

With newly created form displayed in the designer area and open a Toolbox. Right at the top (or elsewhere, depending on your project's name), there should be your WPF user control, ready to drag onto the form. When doing so, Visual Studio will create your control, hosted in the ElementHost control (a Windows Forms control, which can host a WPF element). Set control's size to a desired value and you're done.

image

Download the sample project here.

Tags:

Expression | WPF | Windows Forms | Development

WPF tutorials

by Andrej Tozon 22. January 2008 11:35

If you're starting your development with Windows Presentation Foundation, head over to windowsclient.net, as they're running a great video tutorial series on WPF app development.

Another exhaustive tutorials on designing WPF applications with Expression Blend can be found on the Expression Blend and Design Blog.

And while visiting windowsclient.net, you might as well check out recently released Syndicated Client Experiences Starter Kit & Reader SDK. Remember New York Times Reader? With the SCE starter kit you can build similar experience for delivering your own content to the reader. I have a pretty fixed idea for using this, all I have to do now is find some extra time to pursue it. Anyway, another useful implementation of the SDK is the MSDN Magazine Reader, which also comes with the full source code.

Tags:

WPF | Development

Source Code for .NET Framework Libraries is available

by Andrej Tozon 17. January 2008 10:57

It was announced with the release of Visual Studio 2008, now it's here - follow this thorough step-by-step instructions to enable this new feature; the setup involves a hotfix and some settings tweaking. The last thing to do is agree with the license, and  you'll be able to step through .NET Framework's source code. Cool...

Check also Daniel Moth's video - here.

Tags:

Development

Visual Studio 2008 and Business Intelligence Projects

by Andrej Tozon 29. November 2007 11:41

If you're tempted to uninstall Visual Studio 2005 after installing Visual Studio 2008 (I've done that immediately), a word of caution... There is currently no support for SQL Server 2005 BI projects in Visual Studio 2008. This means that with uninstalling VS2005 you'll lose the ability to, for example, edit Reporting Services 2005 Reports. Support for RS Reports in VS2008 are planned with the SQL Server 2008 release (due next year), but currently there's no plan to support RS 2005 Reports, only 2008.

So... to continue working with SQL Server 2005 projects, you'll have to have Visual Studio 2005 installed, but... not necessarily the whole thing. If you already uninstalled VS2005, but need it just for SQL2005 BI projects, you can now install the VS2005 shell only. Bring out your SQL2005 installation, look for the file vs_install.msi and run it. After a minute or two of silence, the installer should report that installation was successful. SQL Server Business Intelligence Development Studio, together with VS BI templates, is now back [Without all the clutter that "regular" VS2005 installation brings along].

I can't figure out why Microsoft didn't include SQL2005 BI Projects support in VS2008. I mean - with VS2008 you get all these new and improved designers for wide range of technologies, but for BI projects you'll still have to use the old VS2005 shell. I Hope that changes soon.

Tags:

Software | Development

WPF/WinForms Binding Pt.2: Value converters

by Andrej Tozon 3. November 2007 08:46

In previous WPF vs Windows Forms binding post, we left off with pretty useless text binding example - we made the form's title reflect whatever user writes in the textbox:

<Window x:Class="BindingSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="{Binding ElementName=textBox1, Path=Text}" Height="300" 
Width="300" Loaded="Window_Loaded"> ...
</Window>

public Form1()
{
    InitializeComponent();
    DataBindings.Add("Text", textBox1, "Text");
}

We'll extend this example to make it more flexible about outputting text. How about specifying a text template like "This form now belongs to {0}", where {0} would be replaced with whatever user writes in her textbox? We'll do that with the help of value converters.

To create a value converter in Windows Presentation Foundation, all you have to do is implement the IValueConverter interface:

[ValueConversion(typeof(string), typeof(string))]

public
class TextFormatter:
IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (targetType != typeof(string)) { throw new ArgumentException("Target type must be string", "parameter"); } return string.Format(parameter.ToString(), value.ToString()); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }

The Convert method takes a couple of parameters: value is the actual value, being passed in by binding, targetType is the type we're binding to, parameter in our case will serve for passing in the text template. We'll ignore culture as we don't need to support different locales at this time. Since we're not supporting converting the text back to initial value, we'll leave ConvertBack method unimplemented.

Next, we'll include our value converter in the binding definition.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="BindingSample.Window1"
    Height="300" Width="300">
    <Window.Resources>
        <local:TextFormatter x:Key="TextFormatter" />
    </Window.Resources>
    <Window.Title>
        <Binding Path="Text" Converter="{StaticResource TextFormatter}" 
            ConverterParameter="This form now belongs to {0}" 
            ElementName="textBox1" Mode="Default"/>
    </Window.Title>

WPF binding with value converter 

Windows Forms, however, doesn't have something like value converters built in, but you can achieve similar result by using custom classes, which implements similar functionality:

public class SimpleTextFormatter: INotifyPropertyChanged
{
    public string parameter;
    private string value;

    public string Parameter
    {
        get { return parameter; }
        set { parameter = value; }
    }

    public string Value
    {
        get { return value; }
        set
        { 
            this.value = value; 
            OnPropertyChanged("Value"); 
        }
    }

    [Bindable(true)]
    public string FormattedText
    {
        get { return string.Format(Parameter, Value); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

Using this formatter class is again, very simple. First you have to bind form's Text property to formatter's FormattedText property, then bind the input textbox to it's Value property:

public partial class Form1 : Form
{
    private SimpleTextFormatter formatter = new SimpleTextFormatter();

    public Form1()
    {
        InitializeComponent();
       
        formatter.Parameter = "This form now belongs to {0}";
        DataBindings.Add("Text", formatter, "FormattedText");
        textBox1.DataBindings.Add("Text", formatter, "Value", true, DataSourceUpdateMode.OnPropertyChanged);
    }
        ...
}

Again, no events had to be implemented for this to work, it's just the power of data binding, even when used with Windows Forms.

Tags:

WPF | Windows Forms | Development

WPF: When's a Button not a Button

by Andrej Tozon 18. October 2007 04:50

This is a button:

<Button Name="button">Button</Button>

This is a button too:

<ToolBar>
    <Button Name="toolbarButton">Toolbar button</Button>
</ToolBar>

Or is it?

Let's declare a style, targeting a Button type:

<Style TargetType="{x:Type Button}">
    <Setter Property="Background" Value="Green" />
    <Setter Property="Foreground" Value="White" />
</Style>

The result might not be exactly what you expected:

image

Standalone button gets painted according to the declared style, while the button in the ToolBar doesn't. Setting the style explicitly helps:

<ToolBar>
    <Button Name="toolbarButton" 
Style
="{StaticResource ButtonStyle}">Toolbar button</Button
> </ToolBar>

... but that's probably not something we want as we need to apply this style to all the buttons in the given scope.

So what's going on? Well, a ToolBar is a special beast of a control, liking things to be exactly its way, ignoring most of non-direct calls to changing its looks and behavior. It defines and uses some specific resource keys to style its children, and we need to plug into ButtonStyleKey to push our Button style through:

<Style TargetType="{x:Type Button}" x:Key="{x:Static ToolBar.ButtonStyleKey}">
<Setter Property="Background" Value
="Green" />
<Setter Property="Foreground" Value
="White" />
</Style>

Finally, to apply the same style to both common and ToolBar Buttons, we're going to use some of that style inheritance magic:

<Style TargetType="{x:Type Button}" >
    <Setter Property="Background" Value="Green" />
    <Setter Property="Foreground" Value="White" />
</Style>
<Style x:Key="{x:Static ToolBar.ButtonStyleKey}" 
TargetType="{x:Type Button}"
BasedOn="{StaticResource {x:Type Button}}" />
image 
<ToolBar>
    <Button Name="toolbarButton">Toolbar button</Button>
</ToolBar>
<Button Name="button">Button</Button>

Tags:

Layout | WPF | Development



Andrej Tozon
Andrej Tozon's on Twitter View Andrej Tozon's profile on LinkedIn Andrej Tozon's Facebook profile

MVP - Client Application Developer

Microsoft Certified Solution Developer

Currently reading

Month List