Windows 8 First Apps Contest: You are a Finalist!

When Microsoft announced Windows 8 in September 2011 during the Build conference, I was very excited about the incorporation of Metro UI in the OS. Fast and Fluid, truly defined the first impression of Windows 8. I downloaded the Developer Preview and installed it on a virtual machine using VirtualBox. Though I did not succeed in installing it for the first time, I was successful the second time (after numerous searches on the web regarding this topic)! On the virtual machine, to be frank, the experience was not so awesome, but ok. The animations were a bit sluggish.

After installing, I played around with the OS for a few days. I created a few sample apps just to get a hang of metro apps. I was eager to create a major Metro App but was lacking the motivation (yeah, I can be lazy sometimes… :) ).

Then in December, Microsoft announced the Windows 8 First Apps Contest! The thought of having an app of my own as a part of Windows 8 was very appealing. Besides, it gave me the required motivation to delve into Windows 8 programming.

I had created an app called FlipSaw, which is an innovative version of the jigsaw game, in WPF. I was planning to port it to WP7 so that I could release it at the MarketPlace. As the time was short, I decided to port the app to Windows 8 first. The only problem was I had minimal knowledge about Windows 8 programming and I had only 1 week before the deadline of January 8th.

Since the platform is a developer preview, I had a tough time porting the code and getting it to work. I learnt a lot of new things in Windows 8 thanks to the developer community forums. I was able to get the code working only 4 hours before the deadline and couldn’t polish the app much!. Finally I submitted the app with only 15 mins to spare.

Then it was a week long wait. The Build Contest site mentioned that the finalists will be notified via email by Jan 15. But there was no update till Jan 15th 12:59 pm PST (Jan 16th 1.30pm Indian Time). So I thought I didn’t make it. In the evening, the site posted a message that the finalists have been selected and the mails have been sent. I checked my mail again but still my inbox showed zero new mails :(. With a heavy heart, I resolved to update my app anyway when the Beta came out and post it in Windows Store when it opened.

The next day morning, as I was checking my mails, I found a new mail waiting for me in the inbox.

To my utter joy, the subject read – First Apps Contest: You are a Finalist!

Well, I have two more weeks before the deadline of Round 2 (Feb 3rd). This round will be way tougher than the previous round. Time to smoothen the rough edges of my app.

Let’s FlipSaw!!! :)

WPFSpark v1.0 released

Ok, I admit, this post should have been released a few weeks ago, but last few weeks had been pretty hectic and I was unable to post about my pet project WPFSpark which reached the v1.0 milestone last month. Yes, WPFSpark  v1.0  is now released !

I have revamped the CodePlex page to give it a new look. You can access it here.

This release adds four new controls - SparkWindowFluidPivotPanelFluidProgressBar andFluidStatusBar.

It also brings the following improvements to the existing three controls:

  • SprocketControl
    • Internal timer stopped when control is no longer visible. It is started only when the control is Visible. This reduces CPU load.
    • Added the LowestAlpha dependency property which indicates the lowest Opacity value that must be used while rendering the SprocketControl’s spokes.
    • Added the AlphaTicksPercentage dependency property which indicates the percentage of total ticks which must be considered for step by step reduction of the alpha value. The remaining ticks remain at the LowestAlpha value.
    • SprocketControl now implements IDisposable.
  • ToggleSwitch
    • Added the IsCheckedLeft dependency property which indicates whether the checked content appears in the left or right side of the ToggleSwitch
    • Added the CheckedToolTip property which is displayed when the ToggleSwitch is in the Checked state. Set this property to String.Empty( “” ) to prevent this tooltip from displaying.
    • Added the UncheckedToolTip property which is displayed when the ToggleSwitch is in the Unchecked state. Set this property to String.Empty( “” ) to prevent this tooltip from displaying.
  • FluidWrapPanel
    • Added the ItemSource dependency property which can be bound to an ObservableCollection<UIElement>.

Also, I have published articles on CodeProject detailing about the newly added controls . Do check them out. The links are available at the CodePlex site.

HTC Titan – The latest Windows Phone 7.5 beast!

HTC just released their biggest Windows Phone 7.5 smartphone – the HTC Titan! From the first look, it seemed pretty impressive – the large 4.7 inch Super LCD screen, the fluid and elegant Windows Phone 7.5 OS, the 8MP camera with dual flash.
But a much deeper look into the hardware left me disappointed. Here are a few features I would have liked Titan to have to make it a sure winner in the long run-

  • Higher resolution – Having 800×480 on a 4.7″ screen is like watching a 720p movie on an HDTV. A 1280×720 resolution would have been an absolute killer feature.
  • More RAM – Its time we moved from 512MB memory for smartphones to at least 1GB. With multitasking a standard feature in almost all the smartphone OSes, an increased memory would indeed be a blessing.
  • Front facing camera – I expect it to be at least 2-3 MP for a better experience during video calls.
  • Extensibility – the Titan offers no scope of extensibility. An SD slot would have indeed been great.

Apart from all the above points, a major put off would be the price. If HTC can deliver a smartphone with great features at a killer price, it would be a surefire winner!

WPFSpark : 3 of n : FluidWrapPanel

My third article in the WPFSpark series has been published at the CodeProject site.

You can view the article here.

WPFSpark is now available at the NuGet gallery. Get the WPFSpark Nuget package.

Get Notified when child is added to a Custom Panel via XAML

As I was creating the next control for my WPFSpark project – the FluidWrapPanel, a thought occurred to me. How will the FluidWrapPanel be notified when controls are added as its children via XAML?

As of now, FluidWrapPanel had an API called AddChild which would take a UIElement as a parameter. The reason behind this was that the FluidWrapPanel needs to perform some calculations before adding it to the InternalChildren. The UIElementCollection does not have a CollectionChanged to which we can subscribe to. Search over the internet yielded partial solutions to the problem. This MSDN link provided the initial starting point for my solution.

First, I defined an interface INotifiableParent which must be implemented by the Custom Panel requiring UIElementCollection change notification.

namespace WPFSpark
{
    public interface INotifiableParent
    {
        int AddChild(UIElement child);
        void RemoveChild(UIElement child);
    }
}

Next, I derived a class NotifiableUIElementCollection from the UIElementCollection class and provided a constructor, overriden methods (Add and Remove) and private member variable of type INotifiableParent.

namespace WPFSpark
{
    public class NotifiableUIElementCollection : UIElementCollection
    {
        private INotifiableParent parent;

        public NotifiableUIElementCollection(UIElement visualParent, FrameworkElement logicalParent)
            : base(visualParent, logicalParent)
        {
            parent = (INotifiableParent)logicalParent;
        }

        public override int Add(System.Windows.UIElement element)
        {
            if (parent != null)
                return parent.AddChild(element);

            return -1;
        }

        public override void Remove(UIElement element)
        {
            if (parent != null)
                parent.RemoveChild(element);
        }
    }
}

The NotifiableUIElementCollection class does not store the children within itself. Instead it delegates the work to the INotifiableParent member.

Now, the following must be done in the Custom Panel code -

  • Add a member variable of type NotifiableUIElementCollection (this member must be initialized in the constructor!)
  • Add A read-only property of type NotifiableUIElementCollection which returns the private member.
  • The ContentPropertyAttribute must be added to the CustomPanel class with the read-only Property name as the argument.
  • Implement the INotifiableParent interface.

The ContentPropertyAttribute indicates which property of a type is the XAML content property.

Important: In the implementation of the AddChild method, you must add the child to the Children property of the CustomPanel otherwise it will not be rendered on the panel.

Here in the sample panel below, I am expecting that TextBoxes will be added to it via XAML and I am assigning a value to the Text property of the TextBlock.

namespace CustomPanelSample
{
    [ContentProperty("NotifiableChildren")]
    class CustomPanel : Canvas, INotifiableParent
    {
        int count = 1;

        private NotifiableUIElementCollection notifiableChildren;

        public NotifiableUIElementCollection NotifiableChildren
        {
            get
            {
                return notifiableChildren;
            }
        }

        public CustomPanel()
        {
	    // Initialize the NotifiableUIElementCollection
            notifiableChildren = new NotifiableUIElementCollection(this, this);
        }

        #region INotifiableParent Members

        public int AddChild(System.Windows.UIElement child)
        {
            // Add your custom code here
            TextBlock tb = child as TextBlock;

            if (tb != null)
            {
                tb.Text = count++.ToString();
            }

	    // Add the child to the InternalChildren
            return this.Children.Add(child);
        }

        public void RemoveChild(System.Windows.UIElement child)
        {
            this.Children.Remove(child);
        }

        #endregion
    }
}

Here is how the CustomPanel will be used

<Window x:Class="CustomPanelSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="350"
        Width="525"
        xmlns:my="clr-namespace:CustomPanelSample">
    <Grid>
        <my:CustomPanel HorizontalAlignment="Stretch"
                        Margin="15"
                        x:Name="customPanel1"
                        VerticalAlignment="Stretch">
            <TextBlock Width="100"
                       Height="30"
                       Canvas.Left="200"
                       Canvas.Top="10"
                       Foreground="Black"
                       Background="Orchid"
                       FontSize="20"
                       TextAlignment="Center"></TextBlock>
            <TextBlock Width="100"
                       Height="30"
                       Canvas.Left="200"
                       Canvas.Top="50"
                       Foreground="Black"
                       Background="Orchid"
                       FontSize="20"
                       TextAlignment="Center"></TextBlock>
            <TextBlock Width="100"
                       Height="30"
                       Canvas.Left="200"
                       Canvas.Top="90"
                       Foreground="Black"
                       Background="Orchid"
                       FontSize="20"
                       TextAlignment="Center"></TextBlock>
            <TextBlock Width="100"
                       Height="30"
                       Canvas.Left="200"
                       Canvas.Top="130"
                       Foreground="Black"
                       Background="Orchid"
                       FontSize="20"
                       TextAlignment="Center"></TextBlock>
            <TextBlock Width="100"
                       Height="30"
                       Canvas.Left="200"
                       Canvas.Top="170"
                       Foreground="Black"
                       Background="Orchid"
                       FontSize="20"
                       TextAlignment="Center"></TextBlock>
            <TextBlock Width="100"
                       Height="30"
                       Canvas.Left="200"
                       Canvas.Top="210"
                       Foreground="Black"
                       Background="Orchid"
                       FontSize="20"
                       TextAlignment="Center"></TextBlock>
            <TextBlock Width="100"
                       Height="30"
                       Canvas.Left="200"
                       Canvas.Top="250"
                       Foreground="Black"
                       Background="Orchid"
                       FontSize="20"
                       TextAlignment="Center"></TextBlock>
        </my:CustomPanel>
    </Grid>
</Window>

Upon executing this, the following output is shown.

In the NotifiableUIElementCollection, you can also implement the remaining overridable methods available in the UIElementCollection. In that case you must also expand the INotifiableParent interface to accommodate those methods.

Hope this solution comes handy!

Happy coding! :)

WPFSpark : 2 of n : ToggleSwitch

My second article in the WPFSpark series is out. I have added a new control called ToggleSwitch to the WPFSpark library.

You can access it here.

I’m currently finalizing the next control for the WPFSpark library. It is called FluidWrapPanel. You can catch a glimpse of it in my codeplex site.

ClipBorder: A WPF Border that clips

While creating the next control for my WPFSpark project, I had the requirement of a WPF Grid with rounded corners. Since the Grid does not have the CornerRadius property, the other option I had was to encapsulate the Grid within a Border and set the ClipToBounds property of the Border to true. Then I found out that Border (and all decorators) do not perform the clipping even though the ClipToBounds is set to true.

The MSDN Forum provided an excellent solution on how to derive from the Border class and implement the clipping on your own. The ClippingBorder class mentioned in this site has a  _clipRect field (of type RectangleGeometry) which is set as the Clip property of the ClippingBorder’s Child. But in this case the corner radius of the RectangleGeometry is same for all corners. What if you have a border with different corner radius for each corner and you want it to act as a clipping border?

I modified the ClippingBorder class to create the ClipBorder class which will take into account the above mentioned issue. Instead of a RectangleGeometry field, the ClipBorder class uses a PathGeometry to define the clipping Geometry. For this purpose I have used the GeometryHelper class (mentioned in my previous post) to obtain the RoundedRectangleGeometry. I have modified the GeometryHelper code further to take into account the BorderThickness of the ClipBorder.

Here is the code for ClipBorder:

namespace WPFSpark
{
    /// <summary>
    /// Border which allows Clipping to its border.
    /// Useful especially when you need to clip to round corners.
    /// </summary>
    public class ClipBorder : Border
    {
        protected override void OnRender(DrawingContext dc)
        {
            OnApplyChildClip();
            base.OnRender(dc);
        }

        public override UIElement Child
        {
            get
            {
                return base.Child;
            }
            set
            {
                if (this.Child != value)
                {
                    if (this.Child != null)
                    {
                        // Restore original clipping of the old child
                        this.Child.SetValue(UIElement.ClipProperty, oldClip);
                    }

                    if (value != null)
                    {
                        // Store the current clipping of the new child
                        oldClip = value.ReadLocalValue(UIElement.ClipProperty);
                    }
                    else
                    {
                        // If we dont set it to null we could leak a Geometry object
                        oldClip = null;
                    }

                    base.Child = value;
                }
            }
        }

        protected virtual void OnApplyChildClip()
        {
            UIElement child = this.Child;
            if (child != null)
            {
                // Get the geometry of a rounded rectangle border based on the BorderThickness and CornerRadius
                clipGeometry = GeometryHelper.GetRoundRectangle(new Rect(Child.RenderSize), this.BorderThickness, this.CornerRadius);
                child.Clip = clipGeometry;
            }
        }

        private Geometry clipGeometry = null;
        private object oldClip;
    }
}

Update: There was a small error in the calculation of the RoundedRectangle Geometry when the BorderThickness was 1 pixel. I have rectified it and updated the code. Thanks to Gene for pointing it out. :)

Here is the updated code for the modified GeometryHelper:

public static Geometry GetRoundRectangle(Rect baseRect, Thickness thickness, CornerRadius cornerRadius)
{
    // Normalizing the corner radius
    if (cornerRadius.TopLeft < Double.Epsilon)
        cornerRadius.TopLeft = 0.0;
    if (cornerRadius.TopRight < Double.Epsilon)
        cornerRadius.TopRight = 0.0;
    if (cornerRadius.BottomLeft < Double.Epsilon)
        cornerRadius.BottomLeft = 0.0;
    if (cornerRadius.BottomRight < Double.Epsilon)
        cornerRadius.BottomRight = 0.0;

    // Taking the border thickness into account
    double leftHalf = thickness.Left * 0.5;
    if (leftHalf < Double.Epsilon)
        leftHalf = 0.0;
    double topHalf = thickness.Top * 0.5;
    if (topHalf < Double.Epsilon)
        topHalf = 0.0;
    double rightHalf = thickness.Right * 0.5;
    if (rightHalf < Double.Epsilon)
        rightHalf = 0.0;
    double bottomHalf = thickness.Bottom * 0.5;
    if (bottomHalf < Double.Epsilon) 
        bottomHalf = 0.0;

    // Create the rectangles for the corners that needs to be curved in the base rectangle 
    // TopLeft Rectangle 
    Rect topLeftRect = new Rect(baseRect.Location.X, 
                                baseRect.Location.Y, 
                                Math.Max(0.0, cornerRadius.TopLeft - leftHalf), 
                                Math.Max(0.0, cornerRadius.TopLeft - rightHalf)); 
    // TopRight Rectangle 
    Rect topRightRect = new Rect(baseRect.Location.X + baseRect.Width - cornerRadius.TopRight + rightHalf, 
                                 baseRect.Location.Y, 
                                 Math.Max(0.0, cornerRadius.TopRight - rightHalf), 
                                 Math.Max(0.0, cornerRadius.TopRight - topHalf));   
    // BottomRight Rectangle
    Rect bottomRightRect = new Rect(baseRect.Location.X + baseRect.Width - cornerRadius.BottomRight + rightHalf, 
                                    baseRect.Location.Y + baseRect.Height - cornerRadius.BottomRight + bottomHalf, 
                                    Math.Max(0.0, cornerRadius.BottomRight - rightHalf), 
                                    Math.Max(0.0, cornerRadius.BottomRight - bottomHalf)); 
    // BottomLeft Rectangle 
    Rect bottomLeftRect = new Rect(baseRect.Location.X, 
                                   baseRect.Location.Y + baseRect.Height - cornerRadius.BottomLeft + bottomHalf, 
                                   Math.Max(0.0, cornerRadius.BottomLeft - leftHalf),  
                                   Math.Max(0.0, cornerRadius.BottomLeft - bottomHalf)); 

    // Adjust the width of the TopLeft and TopRight rectangles so that they are proportional to the width of the baseRect 
    if (topLeftRect.Right > topRightRect.Left)
    {
        double newWidth = (topLeftRect.Width / (topLeftRect.Width + topRightRect.Width)) * baseRect.Width;
        topLeftRect = new Rect(topLeftRect.Location.X, topLeftRect.Location.Y, newWidth, topLeftRect.Height);
        topRightRect = new Rect(baseRect.Left + newWidth, topRightRect.Location.Y, Math.Max(0.0, baseRect.Width - newWidth), topRightRect.Height);
    }

    // Adjust the height of the TopRight and BottomRight rectangles so that they are proportional to the height of the baseRect
    if (topRightRect.Bottom > bottomRightRect.Top)
    {
        double newHeight = (topRightRect.Height / (topRightRect.Height + bottomRightRect.Height)) * baseRect.Height;
        topRightRect = new Rect(topRightRect.Location.X, topRightRect.Location.Y, topRightRect.Width, newHeight);
        bottomRightRect = new Rect(bottomRightRect.Location.X, baseRect.Top + newHeight, bottomRightRect.Width, Math.Max(0.0, baseRect.Height - newHeight));
    }

    // Adjust the width of the BottomLeft and BottomRight rectangles so that they are proportional to the width of the baseRect
    if (bottomRightRect.Left < bottomLeftRect.Right)
    {
        double newWidth = (bottomLeftRect.Width / (bottomLeftRect.Width + bottomRightRect.Width)) * baseRect.Width;
        bottomLeftRect = new Rect(bottomLeftRect.Location.X, bottomLeftRect.Location.Y, newWidth, bottomLeftRect.Height);
        bottomRightRect = new Rect(baseRect.Left + newWidth, bottomRightRect.Location.Y, Math.Max(0.0, baseRect.Width - newWidth), bottomRightRect.Height);
    }

    // Adjust the height of the TopLeft and BottomLeft rectangles so that they are proportional to the height of the baseRect
    if (bottomLeftRect.Top < topLeftRect.Bottom)
    {
        double newHeight = (topLeftRect.Height / (topLeftRect.Height + bottomLeftRect.Height)) * baseRect.Height;
        topLeftRect = new Rect(topLeftRect.Location.X, topLeftRect.Location.Y, topLeftRect.Width, newHeight);
        bottomLeftRect = new Rect(bottomLeftRect.Location.X, baseRect.Top + newHeight, bottomLeftRect.Width, Math.Max(0.0, baseRect.Height - newHeight));
    }

    StreamGeometry roundedRectGeometry = new StreamGeometry();

    using (StreamGeometryContext context = roundedRectGeometry.Open())
    {
        // Begin from the Bottom of the TopLeft Arc and proceed clockwise
        context.BeginFigure(topLeftRect.BottomLeft, true, true);
        // TopLeft Arc
        context.ArcTo(topLeftRect.TopRight, topLeftRect.Size, 0, false, SweepDirection.Clockwise, true, true);
        // Top Line
        context.LineTo(topRightRect.TopLeft, true, true);
        // TopRight Arc
        context.ArcTo(topRightRect.BottomRight, topRightRect.Size, 0, false, SweepDirection.Clockwise, true, true);
        // Right Line
        context.LineTo(bottomRightRect.TopRight, true, true);
        // BottomRight Arc
        context.ArcTo(bottomRightRect.BottomLeft, bottomRightRect.Size, 0, false, SweepDirection.Clockwise, true, true);
        // Bottom Line
        context.LineTo(bottomLeftRect.BottomRight, true, true);
        // BottomLeft Arc
        context.ArcTo(bottomLeftRect.TopLeft, bottomLeftRect.Size, 0, false, SweepDirection.Clockwise, true, true);
    }

    return roundedRectGeometry;
}
Follow

Get every new post delivered to your Inbox.