Tuesday, November 30, 2010

Observe a Property in MVVM pattern in Silverlight/WPF using Rx

I have been using Rx for over a month now and can’t even begin at telling how beautiful it really is and how much it has simplified my life especially working with UI declaratively and without having to worry about Dispatchers, threading etc., and I ended up rewriting most of the custom controls I have build over time to support Rx. And have been a big fan of Observable pattern and WeakEventListeners again had their own limitation which I always found a bit intimidating and for me Reactive Extensions became the way to go.

Enough of my expression of love for Rx and getting back to the actual blog post. Recently (before I started on Rx) in one of the projects, I was working on (WPF), I had to build a range selector, where the user can select the range by manipulating two sliders. The control was simple enough but then I encountered the problem in the application logic. I have had few very bad experiences with Slider control while creating a video player in good old days of Silverlight 2, and have learned a lesson (the hard way) of never doing long running operations (either async or sync) on any value that might change frequently and having to do sync operation and managing the threads/dispatcher. Well it was a deja vu and a trip to memory lane with long running process on value change of the slider (in this case range selector, well twice as bad). And the long running process was actually to long to turn a blind eye, and the only way out was to stabilise the value before processing long running operation.

Here is what it looked like.

private readonly DispatcherTimer timer = new DispatcherTimer();
DateTime lastTimeTicked;
bool isHandled = false;

void InitialiseValues()
{
    try 
    {
        timer.Interval = TimeSpan.FromMilliseconds(500);
        timer.Tick += new EventHandler(ReCheck);
        //Price is a model object with Start, End properties, bounded two-way to the UI
        //and the event ValuesChanged will be raised on value change of either property. 
        Price.ValuesChanged += (s, e) => StabaliseValues();
        
    }
    catch (Exception ex)
    {
        ...
    }
}

/// <summary>
/// Method to Stabilise Values
/// </summary>
private void StabaliseValues()
{
    if (!timer.IsEnabled)
    {
        timer.Start();
    }
    else
    {
        timer.Stop();
        timer.Start();
    }

    lastTimeTicked = DateTime.Now;
    isHandled = false;
}


/// <summary>
/// Event Handler for Timer.Tick 
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ReCheck(object sender, EventArgs e)
{
    //Already handled 
    if (isHandled)
        return;

    //Double check stability. 
    if (DateTime.Now - lastTimeTicked >= timer.Interval)
    {
        MyLongRunningOperationAsync(); //Run the long running operation async. 
        isHandled = true;
    }
}

Well it worked fine, apart from typical glitches which are common in any async programming scenario. But even though it worked pretty well, it was still a hack with again having to managing the events subscriptions and all that for memory leaks etc.,

When I encountered Rx I went back and the whole code was changed to a very simple extension method call, so the above scenario became,

Observable.FromEvent<EventArgs>(Price, "ValuesChanged")
          .Throttle(TimeSpan.FromMilliseconds(500))
          .Subscribe(_ => MyLongRunningOperationAsync());

This worked fine and all other async problem glitches were resolved using Rx again but this was resolved  only because the there was an event that I was listening to, on the Price; and I was asking myself can we have observable properties instead of events that I can subscribe to?

Since the application logic was in a MVVM pattern and my ViewModel/Model implemented INotifyPropertyChanged interfaces, all my properties that I would be interested in observing already had an event that I can hook up to PropertyChanged, and I can do away with ValuesChanged event so the above scenario became,

Observable.FromEvent<PropertyChangedEventArgs>(Price, "PropertyChanged")
          .Where(evt => evt.EventArgs.PropertyName == "Start" || evt.EventArgs.PropertyName == "End")
          .Throttle(TimeSpan.FromMilliseconds(500))
          .Subscribe(_ => MyLongRunningOperationAsync());

This worked perfectly but to make the process of observing a property better and generic I added some Expression pixie dust, and some reflection love and have ended up with a helper method that would do it all for you,

public static class ReactiveEx
   {

       public static IObservable<T> ObservableProperty<T>(Expression<Func<T>> propertyExtension)
       {
           if (propertyExtension == null)
               throw new ArgumentNullException("propertyExtension");

           var memberExpression = propertyExtension.Body as MemberExpression;

           if (memberExpression == null)
               throw new ArgumentException("The expression is not a member access expression.", "propertyExtension");

           var member = memberExpression.Expression;

           if (member == null)
               throw new ArgumentNullException("the member is not valid", "member");

           var property = memberExpression.Member as PropertyInfo;

           if (property == null)
               throw new ArgumentException("The member access expression does not access a property.", "property");

           var constantExpression = (ConstantExpression)member;

           if (constantExpression.Type.GetInterface("INotifyPropertyChanged") == null)
               throw new ArgumentException("The member doesn't implement INotifyPropertyChanged interface", "constantExpression");

           return Observable
                .FromEvent<PropertyChangedEventArgs>(constantExpression.Value, "PropertyChanged")
                .Where(prop => prop.EventArgs.PropertyName == property.Name)
                .Select(_ => property.GetValue(constantExpression.Value, null))
                .DistinctUntilChanged()
                .Cast<T>();
       }
   }

Using this helper method (which would be executed only once per property) the above scenario would become

ReactiveEx.ObservableProperty(() => Price.Start)
    .Merge(ReactiveEx.ObservableProperty(() => Price.End))
    .Throttle(TimeSpan.FromMilliseconds(500))
    .Subscribe(_ => MyLongRunningOperationAsync());

Now any property can be observed or subscribed to as long as the class implements INotifyPropertyChanged and can use any Rx extension methods to observe your observable property example,

var observer =
    ReactiveEx.ObservableProperty(() => Value)
    .Where(val => val > 0.5d)
    .Do(val => Debug.WriteLine(val))
    .SubscribeOnDispatcher();

IDisposable observerSubscription = 
    observer.Subscribe(
    val => Debug.WriteLine(val, "Value Changed"), 
    ex => Debug.WriteLine("Exception encountered"));

The property observer helper method would work for both WPF 4.0 and Silverlight 4.0.

Monday, September 07, 2009

A brief encounter with Silverlight Multitouch.

Let me first start by saying that I was very much excited about creating a Silverlight multitouch application ever since I heard the announcement that Silverlight supports it, I couldn’t wait to try porting some of our Surface applications to Silverlight.

From a pure feature perspective Silverlight Multitouch doesn’t really provide much since Silverlight Multitouch can only work on  Windows 7 running on a Multitouch capable hardware (HP Touchsmart TX2 in my case) and when you create a web application you can’t expect only 0.001% (probably I am overrating figures here) users to be able to use the application. But all things aside since Microsoft took the trouble of providing Multitouch support in Silverlight 3, I went ahead with the trouble of checking it out.

Although the question of including a non usable feature in Silverlight 3 ahead of other important features (eg., Mic/Web cam support) was raised, the answer I was told was that Surface team was ready with it so they went ahead and included it anyways. I was pretty much satisfied with that answer with anticipation of what I could possibly do with Silverlight Multitouch capabilities.

When the initial excitement died, the first thing that surprised me with that statement was that why would Microsoft take up a decision of including a Multitouch library and unnecessarily increase the plug-in size just for the sake of “Silverlight supports Multitouch” tag line while Silverlight is still struggling with ubiquity against Flash, given the possibilities of what Multitouch in general provides I was pretty sure that there would definitely a huge chuck of framework that might have to be thrown in to at least get it working and it would also mean that all base classes right from UIElement have to be rewritten or wired to support touch and Multitouch, or just like Surface include an interface that will enable touch on existing Silverlight controls but either ways a moderately big chuck of framework have to be thrown at Silverlight.

Alas, I finally got my Multitouch laptop and I was finally able to take a look at Silverlight Multitouch, I was so excited to port our Surface DJ application to Silverlight. My excitement was very short lived, there was only a single static class “System.Windows.Input.Touch” which have nothing except for a single static event “FrameReported”. I cursed, didn’t see that coming, should have, but didn’t.

Nonetheless, I thought maybe I could think of some situation and be able to create some simple application with that might be possible with that one static event and not requiring the whole touch framework. I tried and tried and tried, thought I was doing something wrong when I checked and rechecked couldn’t find anything sinister there, I was pretty sure that my Visual Studio or Silverlight installation might have some problems, there was something fundamentally wrong going on. Don’t want give up… yet…

I went down from a sophisticated application to a very simple one -  two regions (or rectangles) a black and a white, splitting  the whole screen vertically and showing the number of contacts registered on each side, sounds simple right? Wrong! I was getting equal number of contacts on both sides and each one is representing any touch irrespective of where it was touched.

Huh? But why? Where is the sender? Where or how do I know weather the black rectangle got the touch or the white? Without it I obviously can’t know which side was touched. (Don’t get excited I know we can still calculate, just read on),. The EventHandler for the event FrameReported obviously have an parameter “sender”, but since I am not associating my Touch event to any object (rectangle in this case) and since the event itself is a static event, it is always null. I have to look else where… but where?

The EventArgs for the event FrameReported, exposes TouchFrameEventArgs class, which actually includes a property Timestamp (atleast something to hold on to), along with three other methods

  1. GetPrimaryTouchPoint
  2. GetTouchPoints
  3. SuspendMousePromotionUntilTouchUp.

All these methods are self explanatory, although the GetPrimaryTouchPoint and GetTouchPoints takes in a parameter UIElement and returns point/(s) relative to that UIElement, they still doesn’t provide the object or the sender which have actually registered the  touch event.

Ah! Probably since I am attaching the Touch.FrameReported event on whole UserControl I might be getting the touch relative to the whole UserControl. For now, I went ahead and calculated the position of the touch points to get actual touch points on black and white rectangles. Satisfied that I atleast got that working, I wanted to take it to the next level, show random ellipses which only appear for a moment on each region (black/white), and two users can compete with each other, the user who touch on maximum number of these ellipses in a minute wins the game.

Based on the problems I faced previously and my newly formed assumptions I hatched a plan, instead of checking touch on the whole application I will create these ellipses as UserControls and enable touch inside those UserControls, these UserControl on registering a touch will raise an event which will be caught by the main UserControl and do the score and remove that Ellipse visually (so that user can’t touch it again), this way I can identify which UserControl was touched and who should get the points. Promising right?

I went ahead and implemented that, there was only one problem when I touch one ellipse all ellipses were getting removed and both black and white was registering the score! Sigh! What now? On debugging I figure out that if there are two ellipses on the screen the ellipse UserControl is raising the event twice! But why? I am not even touching the second Ellipse, just the one!

No, I am ready to give up… yet.

Maybe… Maybe… since I am also registering Touch on the main screen to determine if black/white region got touch (Which actually took me a while to figure out). Maybe that is the culprit, and since TouchFrameEventArgs inherit from EventArgs and not RoutedEventArgs I can’t suppress the event from bubbling, so the only option with me is to remove it. I went ahead and removed it, made sure that there are no more FrameReported events anywhere in the whole application except for the ellipse user control. Still the same result. But why is it raising the event twice when I touching it only once? Maybe the answer is lurking somewhere in that.

I keep telling myself… don’t give up yet… keep trying, maybe you are doing something wrong…

It came to me suddenly, as a revelation in the form of an accidental touch where there are no ellipses -  breakpoint reached… ellipse raised the event that it got touch. Yeah, you read that right.

Touch in Silverlight is irrelevant of the object that might or might not  be where it got touched, doesn’t matter if its HitTestVisibility is on or off, furthermore it doesn’t even matter if it is visually visible or not, if an “touch enabled” object is included in the visual tree irrespective of any other factor, it will raise that event. And Touch event is only relative to one entity – the whole screen. Even if you want to write your own touch framework, it won’t be possible since Silverlight natively doesn’t support complex HitTesting it would not be feasible to ever determine which objects got the touch, and without that the whole point of Multitouch is irrelevant, unless of course if you are enabling multitouch to your whole application (eg., http://multitouch.soulsolutions.com.au/).

Now coming to the point, Why is it included in Silverlight? Only reasons unknown to mankind. All things said, do I still have an option of not giving up on Silverlight Multitouch? One reason not to give up? I hope and pray that I am doing something wrong, that there is something wrong with my Multitouch driver installation or something else.

But for now my encounter with Silverlight Multitouch is going to be just that – brief.

Sunday, August 02, 2009

Defining Custom VSM states for Custom Controls in Silverlight 3 / Blend 3

In Silverlight 2.0/Expression Blend 2 SP1 creating a new VSM state was pretty straight forward, either for a UserControl or Custom Control a new Visual State could have been created by just clicking on create a new Visual state group, similarly XAML could have been manually editing the XAML.

VisualStateGroup

In Blend 3.0/Silverlight 3.0 you can still create visual states the old way for UserControls but for custom controls this option becomes disabled/unavailable.

CCVisualStateGroup

One reason I could think for this is that all Visual States for a custom control need not be defined in XAML, since most of the time a custom control is build to just show/handle different states but manipulating visual states is part of templating a control for anything other than its default behavior, the most important part as far as Visual States of a Custom Controls is the ability for the control to make a transition from one state to another state, which more than likely happens from the code behind.

It is more important for a Custom Control code behind to know the different states the control and be in than for the XAML which just fires the visual state. In Silverlight 2.0/Blend 2.0 SP1 mapping the visual states created in XAML in code behind by defining Attributes was optional but in Silverlight 3.0 /Blend 3.0 it is the only way to create custom states for a custom control.

By attaching TemplateVisualState Attribute to the Custom Control the visual states can be defined at one place and can be easily manipulated, below is an example of it.

[TemplateVisualState(GroupName = "FocusGroup", Name = "Focus")]
[TemplateVisualState(GroupName = "FocusGroup", Name = "UnFocus")]
[TemplateVisualState(GroupName = "SelectedGroup", Name = "Selected")]
[TemplateVisualState(GroupName = "SelectedGroup", Name = "UnSelected")]
public class SomeCustomControl : Control
{
    public SomeCustomControl()
    {
        this.DefaultStyleKey = typeof(SomeCustomControl);
    }
}

Blend automatically identifies them and allows users to do visual changes to visual states.

 CCVSs

Defining custom visual states this way give developers more power to make the transition between states and since designers don’t have the option of  creating new custom states there will be little confusion between developers/designers.

Wednesday, July 29, 2009

Changing Content Foreground from VSM

Skinning a ListBoxItem/Button or any content element that has its content binded to ContentPresenter and changing it foreground color  often seems impossible, the problem is ContentPresenter doesn’t have the foreground property so you can’t do much for it VisualStateManager. But there are two different ways to achieve this using a trick or hack.

002

Trick:

Modify the template of the ListBoxItem, collapse/Remove the ContentPresenter and add a TextBlock and bind the Text property to TemplateBinding to Content, but ofcourse this would only work if the Content is Text, to apply the same for other complex templates a hack should do.

 

Hack:

Just manually edit the ListBoxItem template and change the ContentPresenter to ContentControl, since ContentControl supports Foreground property you should be able to get the same result, and if the content template is using complex template, the template Foreground should be TemplateBinded to Foreground.

Wednesday, December 24, 2008

Understanding: Dependency Properties in Silverlight

This  is  written to explain Dependency Properties in general as they are available in .NET Framework 3.0 but specifically targeting Silverlight 2.0, in most places effort has been placed to  explain the differences in Dependency Properties in WPF and Silverlight (With Silverlight perspective). But all examples are for Silverlight.

What is Dependency Property?

Dependency properties are new addition to .NET Framework 3.0, Dependency properties are completely new implementation of properties, all programmers are familiar with properties but Dependency properties have a significant amount of added value. They use a sophisticated storage and support higher level features such as property value change notification, property validation, property coercion, property metadata and default property value inheritance. Dependency properties can hold an optional default value, and can propagate the default value down the element tree.

Simply put, a Dependency Property is like any other property but can hold a default value, with built in mechanism for property value validation and automatic notification for changes in property value ( for anyone listening to property value - especially UI)  and any binding in Silverlight is to binded to a Dependency Property.

Dependency Properties Features:

  • Root class must be inherited from UIElement or DependencyObject (Eg., Controls, User Controls, Windows (WPF), or any class derived from UIElement (Button, List, Slider etc.))
  • Dependency Properties have to be registered using DependencyProperty.Register method.
  • Since DependencyProperty.Register is a static (C#) / Shared (VB.NET) method, all dependency properties should also be static/Shared fields, also the property changed callback methods should be static/Shared methods.
  • Any property must be a dependency property if the property is being binded to.
  • By convention, all Dependency Property fields should include the word “Property” at the end of the property name (e.g., for property Value, the Dependency Property name should be ValueProperty).

Defining and Registering a Dependency Property:

While working with .NET 3.0/.NET 3.5 Framework (WPF, Silverlight) you’ll spend more time using Dependency Properties instead of defining them, most of the time you won’t even realise you are using a Dependency Property, but you should be able to create and register Dependency Properties as they are key in designing custom controls, or if you wish to add additional properties for binding, animation or other UI features that would otherwise be not supported.

The syntax of defining a Dependency Property is different from traditional Properties, however features mentioned above should always be remembered while defining Dependency Properties.

Defining Syntax:

VB.NET

Public Class FrameworkElement
    Inherits UIElement

    . . . 
    Public Shared ReadOnly ValueProperty As DependencyProperty

    . . . 

End Class

C#

public class FrameworkElement : UIElement
{

    . . . 

    public static readonly DependencyProperty ValueProperty; 

    . . . 

}

Defining a dependency property is only the first step, in order of the Dependency Property to be used, it should be registered, the registration process also initialises a DependencyObject. 

The Framework ensures that the DependencyProperty objects is not instantised directly since DependencyObjects don’t have public constructors. Hence DependencyObject can only be initialised by using static/Shared DependencyProperty.Register method.

The keyword “Readonly” in the above definition means that the property can only be registered in the static (C#) / Shared (VB.NET) constructor of the class and once registered in can’t be changed(registration) or re-register hence it is readonly, and it doesn’t make the Dependency Property readonly, only that it can’t be reregistered.

Registering Dependency Property

To register the dependency property defined above we have to put them in static/Shared Constructor since they are declared as readonly. 

VB.NET

Public Class FrameworkElement
    Inherits UIElement


    Public Shared ReadOnly ValueProperty As DependencyProperty

    Shared Sub New()
        ValueProperty = DependencyProperty.Register("Value", GetType(Integer), GetType(FrameworkElement), Nothing)
    End Sub


End Class

C#

public class FrameworkElement : UIElement
{

    public static readonly DependencyProperty ValueProperty;

    static FrameworkElement()
    {
        
        ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(FrameworkElement), null);
    }

}

In Silverlight 2.0, static/Shared method of DependencyProperty.Register  takes 4 parameters, there are no overloads available as they are in WPF. 

  1. Name of the property to be registered
  2. Data type of the Dependency Property being registered
  3. Owner (Data type of parent) of the Dependency Property being registered (typically the root class). 
  4. Metadata of the Dependency Property (Optional by specifying null (C#)/Nothing (VB.NET))

Note: You can also define and register DependencyProperty at the same time but you can optionally exclude “readonly” from the DependencyProperty definition.

C#: public static DependencyProperty ValueProperty = DependencyProperty.Register(…);

VB.NET: Public Shared ValueProperty As DependencyProperty = DependencyProperty.Register(…)

 

Reading and Writing Dependency Property values

Once a Dependency Property is defined and registered, you can’t use these properties as traditional .NET properties, Dependency Properties values should be set/get in a different way.

Getting Dependency Property Value

The beauty of Dependency Properties is that it can be used or called by any class or object where the Dependency Property parent class is available (specifically the default value) , even if you haven’t locally defined the parent class, for example you can get the default value down the tree of the parent or child of the class without first initialising the class. The only condition is that the parent class assembly should be made available.

The method to be used to get the value of a Dependency Property is GetValue()

VB.NET  

GetValue(FrameworkElement.ValueProperty)

C#

GetValue(FrameworkElement.ValueProperty); 

Setting Dependency Property Value

Similar to getting the property, setting the property value of a Dependency Property should be done by a method SetValue(), the property name should be with reference to the owner class along with the DependencyProperty.

VB.NET

SetValue(FrameworkElement.ValueProperty, 4)

C#

SetValue(FrameworkElement.ValueProperty, 4);

 

 

 

Property Wrapper

There is a limitation on the methods GetValue and SetValue, in order for a DependencyProperty to be set/get a value the class setting/getting should also be inherited from DependencyObject/UIElement, since GetValue and SetValue methods are inherited from DependencyObject class. In order to overcome this and the simplify the use of Dependency Properties and to make easy and transparent transition (in using) between Dependency Property and Attached Property, Property wrappers are used and are defined within the same class as the definition of Dependency Property.

VB.NET

Public Property Value() As Integer
    Get
        Return GetValue(ValueProperty)
    End Get
    Set(ByVal value As Integer)
        SetValue(ValueProperty, value)
    End Set
End Property

C#

public int Value
{
    get
    {
        return (int) GetValue(ValueProperty);
    }
    set
    {
        SetValue(ValueProperty, value);
    }
}

 

By using property wrappers now the transition between Dependency Properties and normal Properties is transparent, we can carry on using Dependency Properties like we use Properties, in property wrappers any other code like raising an event or validating values should not be included, the wrapper automatically ignores any other code within the wrapper and only looks for SetValue/GetValue methods.

Dependency Property Metadata 

In WPF Dependency Property Metadata is very complex and there are many overloads available but in Silverlight 2.0, Dependency Property Metadata only support two objects, with a maximum of three overloads

  1. Default Value
  2. Property Changed Callback
  3. Default Value, Property Changed Callback

VB.NET

Public Class FrameworkElement
    Inherits UIElement

    Public Shared ReadOnly ValueProperty As DependencyProperty

    Shared Sub New()

        ValueProperty = DependencyProperty.Register("Value", GetType(Integer), GetType(FrameworkElement), _
                  New PropertyMetadata(0, New PropertyChangedCallback(AddressOf FrameworkElementValueChanged)))

    End Sub

    Shared Sub FrameworkElementValueChanged(ByVal sender As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)

    End Sub
End Class

C#

public class FrameworkElement : UIElement
{

    public static readonly DependencyProperty ValueProperty;

    static FrameworkElement()
    {
        
        ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(FrameworkElement), 
            new PropertyMetadata(0, new PropertyChangedCallback(FrameworkElementValueChanged)));
    }

    static void FrameworkElementValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {

    }

} 

In above mentioned examples, the ValueProperty will hold a default value of 0  and every time the value is changed (except for setting the default value), a property changed callback method is invoked (in this example, FrameworkElementValueChanged), the property changed callback should also be a static/Shared method/function, which take two parameters – DependencyObject and DependencyPropertyChangedEventArgs. (This callback method is not generated automatically so the parameters should be remembered for future references).

The DependencyPropertyChangedEventArgs, holds three properties

  1. NewValue
  2. OldValue
  3. Property

The NewValue is the requested value to be changed, the old value is the current value that will be replaced and the property is the identifier of the property requested to be changed, if property changed callback is defined the property value will be changed as soon as the callback method is exited, or in case of a function when a true value is return (to accept the new value) or false (to reject the new value and revert the value to old value).

VB.NET 

Shared Function FrameworkElementValueChanged(ByVal sender As DependencyObject, _
                                            ByVal e As DependencyPropertyChangedEventArgs) As Boolean
        Dim FwE As FrameworkElement = CType(sender, FrameworkElement)
        Dim NVal As Integer = CType(e.NewValue, Integer)
        Dim OVal As Integer = CType(e.OldValue, Integer)

        If (NVal < FwE.Minimum) Then
            Return False
        Else
            Return True
        End If

        If (NVal > FwE.Maximum) Then
            Return False
        Else
            Return True
        End If

 End Function

C#

static bool FrameworkElementValueChanged(DependencyObject sender, 
            DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement FwE = sender as FrameworkElement;
            int NVal = (int)e.NewValue;
            int OVal = (int)e.OldValue;

            if (NVal < FwE.Minimum) return false; else return true;

            if (NVal > FwE.Maximum) return false; else return true;

        }

Since the callbacks methods are also static, you’ll have to cast the sender as the parent class in order for you to use the other methods/properties within the class.

In the above example, if the requested value change is within the Maximum and Minimum value then the new value is accepted or else it is rejected (Note: The callback method being called is a boolean function), this is where you can do your additional updates to any objects depending on the property value or raise events. 

Property Coercion

In WPF, Dependency Property metadata also includes a separate method for property coercion, when a value change is requested, it first execute property coercion callback which can modify the supplied value with property coercion callback, and then property changed callback is called. In Silverlight, Dependency Property metadata is very simple, as mentioned above there is no property coercion callback available, but you can get around that and coerce property value within the property changed callback.

VB.NET

Shared Sub FrameworkElementValueChanged(ByVal sender As DependencyObject, _
                                        ByVal e As DependencyPropertyChangedEventArgs)
    Dim FwE As FrameworkElement = CType(sender, FrameworkElement)
    Dim NVal As Integer = CType(e.NewValue, Integer)
    Dim OVal As Integer = CType(e.OldValue, Integer)

    If NVal < FwE.Minimum Then
        FwE.Value = FwE.Minimum
    End If

    If NVal > FwE.Maximum Then
        FwE.Value = FwE.Maximum
    End If

End Sub

C#

static void FrameworkElementValueChanged(DependencyObject sender, 
    DependencyPropertyChangedEventArgs e)
{
    FrameworkElement FwE = sender as FrameworkElement;
    int NVal = (int)e.NewValue;
    int OVal = (int)e.OldValue;

    if(NVal < FwE.Minimum)
    {
        FwE.Value = FwE.Minimum;
    }

    if(NVal > FwE.Maximum)
    {
        FwE.Value = FwE.Maximum;
    }

}

The above property changed callback is a method instead of a function, where if the requested value change falls beyond the acceptable value it will coerce the value to an acceptable value, in this example if a valid value change is requested and if it exits the method without any change then the value will be accepted.

Limitations of Dependency Property in Silverlight 2.0

Silverlight 2.0 have a very limited control and usage with Dependency Properties, and their existence in Silverlight is only to enable any value to be able to bind to the property rather than provide anything significant. There are many limitation on user defined Dependency properties in Silverlight that its almost unusable in normal circumstances, but in case of user defined custom controls it becomes a compulsion to use dependency properties since binding can only be done to a dependency property and a well built custom control should support binding.

The problem with user defined Dependency Property in Silverlight 2.0 is with the ability to be bind with itself. It can bind to a Dependency Property of another class (if that class is explicitly mentioned as data context). This inability of Dependency Properties renders the use of Dependency Properties in Silverlight to almost useless. Normally (in WPF) you can use a Dependency Property just like a Attached Property, even binding is done with relative easy and user will remain transparent to anything that goes beyond, and by default the context is its own class so there is no problem with binding with itself, but in Silverlight 2.0, Dependency Properties behave differently and should only be used in exceptional circumstances (designing custom controls) and understanding the limitations.

If you are considering using a Dependency Property only to notify changes to property value to UI then you can  use interface System.ComponentModel.INotifyPropertyChanged and use normal Properties instead of Dependency Properties, for example.

VB.NET

Imports System.ComponentModel
Public Class FrameworkElement Implements INotifyPropertyChanged

    Public Event PropertyChanged As PropertyChangedEventHandler _ 
Implements INotifyPropertyChanged.PropertyChanged Private _Value As Integer Public Property Value() As Integer Get Return _Value End Get Set(ByVal value As Integer) If _Value <> value Then _Value = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Value")) End If End Set End Property End Class

C#

using System.ComponentModel;
namespace Elements
{
   public class FrameworkElement : INotifyPropertyChanged
   {

       public event PropertyChangedEventHandler PropertyChanged;

       private int _value;

       public int Value
       {
           get
           {
               return _value;
           }
           set
           {
               if (_value != value)
               {
                   _value = value;
                   PropertyChanged(this, new PropertyChangedEventArgs("Value"));
               }
           }
       }
   }
}

Note: Since in Silverlight an object can’t be binded to any Dependency Property within its own class, its fair to assume that all Dependency Properties in Silverlight are Public.

Microsoft hasn’t explained the limitation on usage of Dependency Properties in Silverlight 2.0, as far as I understand it has to do with the cross platform framework of Silverlight 2.0. But  hopefully Silverlight 3.0 will support advanced Dependency Property options, at least those that we already expect from Silverlight 2.0.

More on Dependency Properties and  Binding, how and why they both are related to each other in next topic to follow - Understanding: Binding in Silverlight.

Friday, October 31, 2008

Developing Custom Controls in Silverlight 2

Introduction

Creating custom controls is not as difficult as they actually appear, but before we go creating custom controls lets first look at the difference between Custom Controls (CC) and Custom User-Controls (CU).

Simply put Custom Controls (CC) are skinable, themable and reusable controls that once created can be used by simply loading the assembly in any project, where are Custom User-Controls are user controls that can be reused but they can't be skinned or themed. Technically they are both difference Custom Controls inherits from (System.Windows.Controls) Controls whereas User Controls inherits from (System.Windows.Controls.UserControl) UserControl. All controls that are used in Silverlight (eg., Button, TextBlock, TextBox) and UserControl is also a Control.

Lets just start by creating a custom control and we can discuss the technicalities where they arise. I'll do this in both C# and VB.NET.

Note: This was my first custom control I built on Silverlight 2 about couple of weeks ago, and I wrote this blog last week as well. I wanted to first introduce concepts like binding and dependency properties before I publish this, but since Microsoft have released Silverlight Toolkit and included NumericUpDown, this is purely academic now. But do enjoy and learn how to create Custom Controls. But the basic concepts are still going to follow.

Developing a Custom Control

In this example we'll create a custom control for NumericUpDown. Its a very simple control that can be easily built, I'll be using Microsoft Visual Studio 2008 and Microsoft Expression Blend 2 (SP1), we don't really need Expression Blend but sometimes it saves time using Expression Blend.

First, we'll set up and prepare to built a custom control and to test it.

1. Setup:

In Visual Studio Start a new Project with Silverlight Application Template and name it (I named it Silverlight Control Library), then select ASP.NET Web Application Project for testing.

2008-10-25_141920 2008-10-25_141938

Now the project for testing is ready and we need a new Silverlight Class Library Template project within the solution, so add new project and Name it (I named it Controls), this is where we'll be building our custom controls, by default you'll have a Class1.vb or Class1.cs file in the project delete the file, and add a new folder and rename it "themes" (The name of this folder is important, so keep it like it is). 

2008-10-25_142351 2008-10-25_142446 2008-10-25_142514

Now add an empty xaml file in that folder and name it "generic.xaml" (Again the name is important), add the following XAML tags in the the xaml file, this is the basic shell we'll always need in building custom controls.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
    <Style>
        
    </Style>
</ResourceDictionary>

It is very important that you remember to make the generic.xaml build action as Resource, this is to make sure that the template is packed in the same assembly as the control otherwise the template wont be available.

2008-10-25_210935

Add another folder and name it "NumericUpDown", this is where we'll be building our custom control.

2008-10-25_142528 2008-10-25_142541 2008-10-25_142558

2: Preparing

Now that the setup is complete we can start building the control but first we need to focus and gather facts about the custom control.

  1. Is a Numeric Only TextBox with 2 buttons for increasing and decreasing the value.
  2. Will have a Minimum and Maximum, along with an actual Value.
  3. TextBox should only take numeric input along with Up/Down buttons
  4. Optionally control can be made to use only Up/Down instead of directly entering the value in the TextBox.
  5. When the value is changed, the control will raise an event to notify anyone listening, with its own EventArgs.
  6. The Control should allow access and Binding on basic properties like IsEnabled, Foreground, Font Size etc.

3: Building

First, we'll add a Class file in "NumericUpDown" folder and name it "NumericBox", this will be the name of the control, but like I explained before all controls should inherit from Control, second you'll have to tell the compiler where default style for the control is, in order to do this we'll set the DefaultStyleKey value, so in constructor.

C#

public class NumericBox: Control
   {
       public NumericBox()
       {
           DefaultStyleKey = typeof(NumericBox);
       }
   }

VB.NET

Public Class NumericBox
    Inherits Control

    Public Sub New()
        DefaultStyleKey = GetType(NumericBox)
    End Sub

End Class

Now the constructor will look for default style in generic.xaml (under themes folder) for any style referencing to current assembly. 

Now we'll expose some properties externally for anyone to bind, you should be aware that any external property you want to bind to the control should be a DependencyProperty, any property (Attached Property / Dependency Property) can be binded but the property that it is binding to should be a DependencyProperty, so to keep this control bindable we'll have to expose Dependency Properties, If you have problem following this, leave a message and I'll try to explain DependencyProperty in detail.

Now, we already know that we need to expose three properties Minimum, Maximum and Value, in order for us to able to check if the values entered are valid we'll check them every time the any property is changed by using PropertyChangedCallback. (We'll implement Property Callbacks later)

C#

#region Dependency Properties
       public int Minimum
       {
           get { return (int)GetValue(MinimumProperty); }
           set { SetValue(MinimumProperty, value); }
       }

       public static readonly DependencyProperty MinimumProperty =
           DependencyProperty.Register("Minimum", typeof(int), typeof(NumericBox), 
           new PropertyMetadata(0, new PropertyChangedCallback(MinimumChanged)));

       private static void MinimumChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {

       }

       public int Maximum
       {
           get { return (int)GetValue(MaximumProperty); }
           set { SetValue(MaximumProperty, value); }
       }

       public static readonly DependencyProperty MaximumProperty =
           DependencyProperty.Register("Maximum", typeof(int), typeof(NumericBox), 
           new PropertyMetadata(10, new PropertyChangedCallback(MaximumChanged)));

       private static void MaximumChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {

       }

       public int Value
       {
           get { return (int)GetValue(ValueProperty); }
           set { SetValue(ValueProperty, value); }
       }

       public static readonly DependencyProperty ValueProperty =
           DependencyProperty.Register("Value", typeof(int), typeof(NumericBox),
           new PropertyMetadata(0, new PropertyChangedCallback(ValueChanged)));

       private static void ValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {

       }

#endregion

VB.NET

#Region "Dependency Properties"

    Public Property Minimum()
        Get
            Return GetValue(MinimumProperty)
        End Get
        Set(ByVal value)
            SetValue(MinimumProperty, value)
        End Set
    End Property

    Public Shared MinimumProperty As DependencyProperty = _
    DependencyProperty.Register("Minimum", GetType(Integer), GetType(NumericBox), _
                            New PropertyMetadata(0, New PropertyChangedCallback(AddressOf MinimumValueChanged)))

    Private Shared Sub MinimumValueChanged(ByVal sender As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)

    End Sub

    Public Property Maximum()
        Get
            Return GetValue(MaximumProperty)
        End Get
        Set(ByVal value)
            SetValue(MaximumProperty, value)
        End Set
    End Property

    Public Shared MaximumProperty As DependencyProperty = _
    DependencyProperty.Register("Maximum", GetType(Integer), GetType(NumericBox), _
                                New PropertyMetadata(10, New PropertyChangedCallback(AddressOf MaximumValueChanged)))

    Private Shared Sub MaximumValueChanged(ByVal sender As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)

    End Sub

    Public Property Value()
        Get
            Return GetValue(ValueProperty)
        End Get
        Set(ByVal value)
            SetValue(ValueProperty, value)
        End Set
    End Property

    Public Shared ValueProperty As DependencyProperty = _
    DependencyProperty.Register("Value", GetType(Integer), GetType(NumericBox), _
                                New PropertyMetadata(0, New PropertyChangedCallback(AddressOf ValueChanged)))

    Private Shared Sub ValueChanged(ByVal sender As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)


    End Sub

#End Region

Now we have three Dependency Properties exposed, we are setting the default values here but its a good practice to also set them in Style, so we'll go to generic.xaml (after compiling the project) and add a reference to current assembly and then add them to the style.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
    xmlns:local="clr-namespace:Controls.NumericUpDown;assembly=Controls.NumericUpDown">
    
        <Style TargetType="local:NumericBox">
            <Setter Property="Minimum"  Value="0"/>
            <Setter Property="Maximum" Value="10"/>
            <Setter Property="Value" Value="0"/>
        </Style>
</ResourceDictionary>
    

Now that you understand how to expose properties, we'll first finish the job with Dependency Properties by validating the values.

C#

private static void MinimumChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    NumericBox NB = sender as NumericBox;

    int val = (int)e.NewValue;

    if (NB == null)
        return;

    if (val > NB.Maximum)
        NB.Minimum = (int)e.OldValue;

    if (NB.Value < val)
        NB.Value = val;
}

private static void MaximumChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    NumericBox NB = sender as NumericBox;

    int val = (int)e.NewValue;

    if (NB == null)
        return;

    if (val < NB.Minimum)
        NB.Maximum = (int)e.OldValue;
}

private static void ValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    NumericBox NB = sender as NumericBox;
    int val = (int)e.NewValue;
    if (NB == null)
        return;

    if (val < NB.Minimum)
    {
        NB.Value = NB.Minimum;
        NB._ValueChanged = false;
        return;
    }

    if (val > NB.Maximum)
    {
        NB.Value = NB.Maximum;
        NB._ValueChanged = false;
        return;
    }
    NB._ValueChanged = true;    
}

VB.NET

Private Shared Sub MinimumValueChanged(ByVal sender As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)

    Dim NB As NumericBox = CType(sender, NumericBox)
    Dim Val As Integer = CType(e.NewValue, Integer)

    If NB Is Nothing Then Return

    If Val >= NB.Maximum Then NB.Minimum = CType(e.OldValue, Integer)

    If Val > NB.Value Then NB.Value = Val

End Sub

Private Shared Sub MaximumValueChanged(ByVal sender As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)

    Dim NB As NumericBox = CType(sender, NumericBox)
    Dim Val As Integer = CType(e.NewValue, Integer)

    If NB Is Nothing Then Return

    If Val <= NB.Minimum Then NB.Maximum = CType(e.OldValue, Integer)

    If Val < NB.Value Then NB.Value = Val

End Sub

Private Shared Sub ValueChanged(ByVal sender As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)

    Dim NB As NumericBox = CType(sender, NumericBox)
    Dim Val As Integer = CType(e.NewValue, Integer)

    If NB Is Nothing Then Return

    If Val < NB.Minimum Then
        NB.Value = NB.Minimum
        NB._ValueUpdated = False
        Return
    End If

    If Val > NB.Maximum Then
        NB.Value = NB.Maximum
        NB._ValueUpdated = False
        Return
    End If

    NB._ValueUpdated = True
End Sub

Now that basic logic is in place we'll finish with the basic structure, for this we need to define template in generic.xaml to provide the building blocks of the control (i.e., the look and feel of the control).

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
    xmlns:local="clr-namespace:Controls.NumericUpDown;assembly=Controls.NumericUpDown">
    
        <Style TargetType="local:NumericBox">
            <Setter Property="Minimum"  Value="0"/>
            <Setter Property="Maximum" Value="10"/>
            <Setter Property="Value" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                  <ControlTemplate TargetType="local:NumericBox">
                       <Grid>
                          <Grid.ColumnDefinitions>
                              <ColumnDefinition Width="3*"/>
                               <ColumnDefinition Width="*"/>
                           </Grid.ColumnDefinitions>
                         <TextBox x:Name="NumericTextBox"  Grid.Column="0" Grid.ColumnSpan="2" IsTabStop="True"
                                  IsEnabled="{TemplateBinding IsEnabled}" 
                                  Foreground="{TemplateBinding Foreground}"
                                  Background="{TemplateBinding Background}"
                                  Visibility="{TemplateBinding Visibility}"
                                  Text="{TemplateBinding Value}"
                                  />
                         <Grid Grid.Column="1">
                             <Grid.RowDefinitions>
                                 <RowDefinition/>
                                 <RowDefinition/>
                             </Grid.RowDefinitions>
                             <Button x:Name="ValUp" Grid.Row="0" Margin="0,1,1,0" IsTabStop="False"
                                  IsEnabled="{TemplateBinding IsEnabled}"
                                  Background="{TemplateBinding Background}"
                                  Visibility="{TemplateBinding Visibility}"
                                  >
                                 <Path Fill="{TemplateBinding Foreground}" 
                                       Data="F1 M 4.81721,-3.05176e-005L 9.63441,8.3436L 2.49481e-006,8.3436L 4.81721,-3.05176e-005 Z "/>
                             </Button>
                             <Button x:Name="ValDown" Grid.Row="1" Margin="0,0,1,1" IsTabStop="False"
                                     IsEnabled="{TemplateBinding IsEnabled}"
                                     Background="{TemplateBinding Background}"
                                     Visibility="{TemplateBinding Visibility}"
                                     >
                                 <Path Fill="{TemplateBinding Foreground}" 
                                       Data="F1 M 4.81721,8.34363L 9.63441,0L 2.49481e-006,0L 4.81721,8.34363 Z "/>
                             </Button>
                         </Grid>
                     </Grid>
                    </ControlTemplate>
             </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
   

Note that we have binded all external properties to both the TextBox or Buttons, and pay attention that the Buttons and the TextBox have names, we use these names in our control class to access these objects to access events associated with them, if for some reason the names in the control templates change (user defined template/Skinned template), the whole control will fall apart, and there is no simple way to deal with it (we can deal with this by accessing the root element and checking its children, but that is a different story)

Now we have to access four events, TextBox.TextChanged, TextBox.KeyDown, ButtonUp.Click and ButtonDown.Click to do this we'll overload/override "OnApplyTemplate" Method, it has to be noted that you can't access the template from constructor, even though we set the DefaultKeyStyle in constructor so the only way to safely access the objects and capture events is to do it when the template is applied, you can get a child from the template using "GetTemplateChild" method.

C#

private TextBox TBxNum;
private Button ButUp;
private Button ButDw;

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    TBxNum = base.GetTemplateChild("NumericTextBox") as TextBox;
    ButUp = base.GetTemplateChild("ValUp") as Button;
    ButDw = base.GetTemplateChild("ValDown") as Button;

    if (TBxNum == null)
        return;

    if (ButUp == null)
        return;

    if (ButDw == null)
        return;

    TBxNum.TextChanged += new TextChangedEventHandler(TBxNum_TextChanged);
    TBxNum.KeyDown += new KeyEventHandler(TBxNum_KeyDown);
    ButUp.Click += new RoutedEventHandler(ButUp_Click);
    ButDw.Click += new RoutedEventHandler(ButDw_Click);
}

VB.NET

Private TBxNum As TextBox
Private ButUp As Button
Private ButDw As Button


Public Overloads Overrides Sub OnApplyTemplate()
    MyBase.OnApplyTemplate()

    TBxNum = CType(MyBase.GetTemplateChild("NumericTextBox"), TextBox)
    ButUp = CType(MyBase.GetTemplateChild("ValUp"), Button)
    ButDw = CType(MyBase.GetTemplateChild("ValDown"), Button)

    If TBxNum Is Nothing Then Return

    If ButUp Is Nothing Then Return

    If ButDw Is Nothing Then Return

    AddHandler TBxNum.TextChanged, AddressOf TBxNum_TextChanged
    AddHandler TBxNum.KeyDown, AddressOf TBxNum_KeyDown
    AddHandler ButUp.Click, AddressOf ButUp_Click
    AddHandler ButDw.Click, AddressOf ButDw_Click
End Sub

We need to capture Button.Click events to Up/Down the Value, but we are defining TextBox.KeyDown event to restrict the entry of non-numeric keys in the text box, and we'll update Value when the Value is typed in the TextBox, thats why we are capturing the TextBox.TextChanged Event, although we are already restricting the keyboard entry I still prefer to check if the Value entered in the TextBox is a number, and we can update the Value in one procedure.

C#

void TBxNum_TextChanged(object sender, TextChangedEventArgs e)
{
    if (Single.IsNaN(System.Convert.ToSingle(TBxNum.Text)))
        throw new NotFiniteNumberException(TBxNum.Text);
    else
       UpdateValue((int)System.Convert.ToInt64(TBxNum.Text));
}

void TBxNum_KeyDown(object sender, KeyEventArgs e)
{
    if (((e.Key >= Key.D0 && e.Key <= Key.D9) || (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9) || e.Key == Key.Back))
        e.Handled = false;
    else
    {
        e.Handled = true;
    }
}

void ButUp_Click(object sender, RoutedEventArgs e)
{
    UpdateValue(Value + 1);
}

void ButDw_Click(object sender, RoutedEventArgs e)
{
    UpdateValue(Value - 1);
}

void UpdateValue(int val)
{
    _ValueChanged  = false;
    Value=int;
    if(_ValueChanged) 
    {
        TBxNum.Text = Value.ToString();
    }
}

VB.NET

Private Sub TBxNum_TextChanged(ByVal sender As Object, ByVal e As TextChangedEventArgs)
    If (Single.IsNaN(System.Convert.ToSingle(TBxNum.Text))) Then
        Throw New NotFiniteNumberException(TBxNum.Text)
    Else
        UpdateValue(CType(TBxNum.Text, Integer))
    End If
End Sub

Private Sub TBxNum_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
    If ((e.Key >= Key.D0 And e.Key <= Key.D9) OrElse (e.Key >= Key.NumPad0 And e.Key <= Key.NumPad9) _
        OrElse e.Key = Key.Back) Then e.Handled = False Else e.Handled = True
End Sub

Private Sub ButUp_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    UpdateValue(Value + 1)
End Sub

Private Sub ButDw_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    UpdateValue(Value - 1)
End Sub

Private Sub UpdateValue(ByVal val As Integer)
    _ValueUpdated = False
    Value = val
    If _ValueUpdated Then
        TBxNum.Text = val
    End If
End Sub

Now the control is up and ready for testing(don't forget to add reference to this assembly), you can make any changes to the source code as you see it fit, the only thing left is to raise an event when the value changes in case anyone is listening. For this we'll build a custom EventArgs to pass the changed value.

So add another file in the folder and name it "NumericBoxChangedArgs.cs" or "NumericBoxChangedArgs.vb"  as shown below.

2008-10-26_092756

Now, the NumericBoxChangedArgs class inheirts EventArgs and have a readonly property and a constructor to set the Value changed, it also have a delegate event handler with NumbericBoxChangedArgs signature.

C#

 

public delegate NumericBoxChangedHandler(object sender, NumericBoxChangedArgs e);

public class NumericBoxChangedArgs : EventArgs
{
    private readonly int _Value;

    public NumericBoxChangedArgs(int val)
    {
        _Value = val;
    }

    public int Value
    {
        get
        {
            return _Value;
        }
    }
}

VB.NET

Namespace NumericUpDown
    Public Delegate Sub NumericBoxChangedHandler(ByVal sender As Object, ByVal e As NumericBoxChangedArgs)

    Public Class NumericBoxChangedArgs
        Inherits EventArgs

        Private ReadOnly _val As Integer

        Public Sub New(ByVal val As Integer)
            _val = val
        End Sub

        Public ReadOnly Property Value() As Integer
            Get
                Return _val
            End Get
        End Property

    End Class
End Namespace

Now we just declare the delegate locally and raise event in it in UpdateValue procedure.

C#

public event NumericBoxChangedHandler NumericBoxChanged;

void UpdateValue(int val)
{
    _ValueChanged  = false;
    Value=int;
    if(_ValueChanged) 
    {
        TBxNum.Text = Value.ToString();
        NumericBoxChangedArgs NArgs = new NumericBoxChangedArgs(Value);
        NumericBoxChanged(this, NArgs);
    }
}

VB.NET

Public Event NumericBoxChanged As NumericBoxChangedHandler

Private Sub UpdateValue(ByVal val As Integer)
    _ValueUpdated = False
    Value = val
    If _ValueUpdated Then
        TBxNum.Text = Value
        Dim NArgs As New NumericBoxChangedArgs(Value)
        RaiseEvent NumericBoxChanged(Me, NArgs)
    End If
End Sub

All the points mentioned while preparing the control are now achieved (I have added couple of more Dependency Properties to the source code (IncrementStep, IncrementOnly). Our Custom Numeric Up/Down Box is now complete, you can download the source code for this custom control below, if you make any modifications to the source code, please let me know.

Licence

Creative Commons License
Silverlight NumericUpDown Control by Imran Shaik is licensed under a Creative Commons Attribution-Non-Commercial-Share Alike 2.0 UK: England & Wales License.
Based on a work at www.geekswithblogs.net.

Download Source Code/Binary

Version 1.0 (Both VB.NET & C#)

Sunday, October 26, 2008

Understanding/Developing Silverlight

There are many tutorials in Silverlight over the Internet that mostly cover the basics of Silverlight but when you start getting a bit ahead you get into trouble and the real lack of tutorials or examples when you get to Intermediate level and beyond there is much to be desired especially when it comes in examples on MSDN (specifically VB.NET), so I am starting a new series which I hope will cover from basic to advanced level, and I might try to go in as much detail as possible, basically I am finding it hard to make the transition from WPF to Silverlight and this blog series will be my way of keeping notes.

I might not get it right the first time or I might miss a few things so you are always welcome to correct and rectify me if I make any mistakes. The series isn't arranged in any order I'll just blog them as they leap in my mind, I might not blog some concepts but you are always welcome to post requests.

In near future I hope to post atleast the following (the order may change)

  1. Understanding: Silverlight Binding
  2. Understanding: Silverlight Dependency Properties
  3. Understanding: Silverlight User Controls
  4. Understanding: Silverlight Custom Controls
  5. Understanding: Dynamic Silverlight
  6. Understanding: Dynamic Silverlight XAML
  7. Understanding: Silverlight Templates

In addition, I'll also bring you examples in Developing series which use the concepts in Understanding series and develop real-world applications both in C# and VB.NET, and in this series you might see

  1. Developing: Custom User Controls
  2. Developing: Custom Controls
  3. Developing: Dynamic Custom Controls
  4. Developing: Commercial Applications

Have some patience and stay tuned.

Friday, October 24, 2008

Tutorial: Animating Custom Controls for themes using Opacity Masks

As promised I'm going to show you how to animate custom controls using Opacity masks, if you are unfamiliar with Opacity masks, please check my previous blog entry: Working with Opacity masks

In this tutorial we'll create a custom button, animate it for mouse events and then still keep it flexible to them it

The Problem

Custom controls are notorious, especially when it comes to applying themes, it is very simple to create a custom button and animate it but it all falls apart when you try to keep it flexible to apply your themes, for example you can create a button apply animations on mouse enter and pressed states but then you can't keep your colour for external binding.

Solution:

Instead of applying animation to the colour itself you can apply animation to the opacity masks and keep the theme alive for external colour binding, here is how we'll go about it using Expression Blend .

I am sorry for the audio but its pretty simple to follow.

Silverlight Streaming (http://silverlight.live.com) is not working so please download the video

Note: At 2:20 I copied and pasted another Rectangle on back of the the main rectangle and coloured it black to avoid the transparency of opacity mask, it is a good practice in order to avoid making the button (or control in general) transparent, don't forget to experiment the background by using gradient brushes published before (Tip: With this Opacity Mask try the Large set of gradients for good effect).

Download

Download Source code (ThemedButton.Zip 34KB)

Wednesday, October 22, 2008

Working with Opacity Masks

Opacity Masks are a great addition to Silverlight even thought it was there from the beginning, they are not as much helpful as otherwise they might be due to the lack of brushes in Silverlight (compared to WPF). And the addition of Alpha along with RGB in colour definition, opacity masks don't really gain much attention as they deserve. Although the use of Opacity Masks in Silverlight is very limited it is nonetheless a less important features, especially in animations and applying both vertical and horizontal gradients or both linier and radial gradient to the same object let us from start with looking at what opacity masks are and then how opacity masks are helpful in applying both vertical and horizontal gradients to the same object.

As you might already know that you can only attach one single colour schema (Either Solid colour or gradients) to an object, so we'll first begin with looking at what opacity masks are.

Opacity Masks.

First we'll look at what opacity masks do on a solid colour, and then we'll go in detail with complex gradients.

 2008-10-22_192437

Image 1: Rectangle with Solid colour

<Rectangle Fill="#FF0B1BC6" Stroke="#FF000000" RadiusX="8" RadiusY="8"/>

Now I have an object with solid colour (Rectangle with Colour FF0B1BC6 in this case) and lets say that we want to apply some transparency to the the object either at the beginning or at the end, so since Silverlight have Alpha channel in its colour definition along with RGB definition its simple to use it, Since we are dealing with a solid colour here its easy to just create a liner gradient with alpha reduced e.g.,

2008-10-22_192457

Image 2: Rectangle with Linear gradient with opacity

<Rectangle RadiusX="8" RadiusY="8" Stroke="#FF000000">
    <Rectangle.Fill>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="#7F0B1BC6"/>
            <GradientStop Color="#FF0B1BC6" Offset="1"/>
        </LinearGradientBrush>
    </Rectangle.Fill>
</Rectangle>

Notice the Colour between two gradient stops they are the same colour (0B0BC6) the only difference is the Alpha (7F and FF), at offset 0 (beginning of the gradient) we have 50% opacity and at the offset 1 (end of the gradient) we have 100% opacity.

It works but we can also achieve he same by applying opacity mask to the rectangle in Image 1,

2008-10-22_193332

Image 3: Rectangle with opacity mask

<Rectangle Fill="#FF0B1BC6" Stroke="#FF000000" RadiusX="8" RadiusY="8">
    <Rectangle.OpacityMask>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="#7F000000" Offset="0"/>
            <GradientStop Color="#FFFFFFFF" Offset="1"/>
        </LinearGradientBrush>
    </Rectangle.OpacityMask>
</Rectangle>

Notice Image 2 and Image 3, the difference isn't much, infact technically there isn't any difference because both of them are one and the same, the only difference is applying the opacity mask to a solid colour have achieved the same results as actually applying a gradient.

Uses of Opacity Mask

You might ask well if we can achieve the same results with both gradient and applying opacity mask then why use opacity mask, well the advantages of opacity masks are very clear, consider this you can only apply one gradient to an object but with the addition of opacity mask you can achieve both at the same time.

Here is an example,

Consider the following gradient

2008-10-22_194405 

Image 4: Rectangle with liner gradient from left to right

Now consider that we want darken the rectangle on the top and leave the bottom the same, given that we can only apply one gradient for a single object, so to achieve this we'll have to put the another rectangle on top of that with a black gradient running from top to bottom, and  giving the top about 50% opacity and the bottom 0% opacity.

Instead we can use opacity masks to achieve this,

2008-10-22_195548

Image 5: Rectangle gradient (left to right) with opacity mask (top to bottom)

 

<Rectangle RadiusX="8" RadiusY="8" Stroke="#FF000000">
            <Rectangle.OpacityMask>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#7E000000" Offset="0.4"/>
                    <GradientStop Color="#FF000000" Offset="1"/>
                    <GradientStop Color="#B2000000" Offset="0.5"/>
                </LinearGradientBrush>
            </Rectangle.OpacityMask>
            <Rectangle.Fill>
                <LinearGradientBrush EndPoint="1.,0.5" StartPoint="0,0.5" >
                    <GradientStop Color="#FFC60B0B" Offset="0"/>
                    <GradientStop Color="#FFC60B0B" Offset="1"/>
                    <GradientStop Color="#FFAAB30C" Offset="0.175"/>
                    <GradientStop Color="#FE3B8C41" Offset="0.31"/>
                    <GradientStop Color="#FE2E6C6F" Offset="0.48"/>
                    <GradientStop Color="#FE21258D" Offset="0.70"/>
                    <GradientStop Color="#FE9E19A1" Offset="0.85"/>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

This trick is usually used in making the glass effects with gradients, and it is limited to dark backgrounds since in reality the opacity mask is actually making the object transparent than actually making it darker or lighter, which brings us to another usage of opacity masks.

Partially transparent objects, captures the imagination, and you can achieve them using opacity masks, for example consider the following image, its the same rectangle in Image 5 over other rectangles.

2008-10-22_200437

Objects using Opacity Masks

Opacity masks are not limited to objects rectangles or paths or gradients, opacity masks can also be applied to various objects to give partial transparency, including and not limited to images and vides infact you can apply opacity masks to all UI elements and you can apply any brush (Graident brush/image brush/Video Brush etc.) as a base for opacity mask.

Opacity Masks in Silverlight 2 are limited since other brushes (those available in WPF) are not available in Silverlight, but probably probably they might be avialble in future versions of Silverlight.

Opacity Masks and animation and themes

One of the areas where I usually use opacity masks are in themes and animation, I'll soon post a tutorial on using opacity masks in animation/ themes and in creating custom controls and templates, watch this space.

Tuesday, October 21, 2008

More XAML Gradients

This is my second lot of Gradients they are few more but that is for some other day, here are about 14 new gradients for you, I need some patience and inspiration to make few so I might come back with more.

2008-10-21_165944 

XAML:

    <LinearGradientBrush x:Key="CyanThemeBG" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFC6ECFE"/>
        <GradientStop Color="#FF003FFF" Offset="1"/>
        <GradientStop Color="#FF37AFF9" Offset="0.5"/>
        <GradientStop Color="#FF0076DB" Offset="0.5"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="MagentaBG" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFFFCFFB" Offset="0"/>
        <GradientStop Color="#FF930E2F" Offset="1"/>
        <GradientStop Color="#FFFF659D" Offset="0.5"/>
        <GradientStop Color="#FFC7174B" Offset="0.5"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="BlackBG" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFE5E7FA"/>
        <GradientStop Color="#FF747C8D" Offset="0.5"/>
        <GradientStop Color="#FF000000" Offset="0.5"/>
        <GradientStop Color="#FF0F0F0F" Offset="1"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="LightBG" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFE5E7FA"/>
        <GradientStop Color="#FFE3E6F5" Offset="0.5"/>
        <GradientStop Color="#FFD5DBF1" Offset="0.5"/>
        <GradientStop Color="#FFE1E4FF" Offset="1"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="TealGreen" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFE3FCA9" Offset="0"/>
        <GradientStop Color="#FF82B03C" Offset="1"/>
        <GradientStop Color="#FFD8FA6C" Offset="0.5"/>
        <GradientStop Color="#FFE0FF98" Offset="0.5"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="CyanLargeBG" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FF003FFF" Offset="1"/>
        <GradientStop Color="#FF37AFF9" Offset="0"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="MagentaLargeBG" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FF930E2F" Offset="1"/>
        <GradientStop Color="#FFFF659D" Offset="0"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="LightLargeBG" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFE3E6F5" Offset="0"/>
        <GradientStop Color="#FF9D9D9D" Offset="1"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="GreenLargeBG" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FF82B03C" Offset="1"/>
        <GradientStop Color="#FFD8FA6C" Offset="0"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="PurpleBG" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFB0B8FF"/>
        <GradientStop Color="#FF747C8D" Offset="0.5"/>
        <GradientStop Color="#FF000000" Offset="0.5"/>
        <GradientStop Color="#FF151733" Offset="1"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="DarkGreen" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFB0FFC4"/>
        <GradientStop Color="#FF5D645F" Offset="0.5"/>
        <GradientStop Color="#FF000000" Offset="0.5"/>
        <GradientStop Color="#FF15331F" Offset="1"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="DarkYellow" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFF3FFB0"/>
        <GradientStop Color="#FF63645D" Offset="0.5"/>
        <GradientStop Color="#FF000000" Offset="0.5"/>
        <GradientStop Color="#FF2F3315" Offset="1"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="DarkGrape" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFFFB0FD"/>
        <GradientStop Color="#FF8D7485" Offset="0.5"/>
        <GradientStop Color="#FF000000" Offset="0.5"/>
        <GradientStop Color="#FF331532" Offset="1"/>
    </LinearGradientBrush>
    <LinearGradientBrush x:Key="DarkBrown" EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="#FFFFEAB0"/>
        <GradientStop Color="#FF8D8774" Offset="0.5"/>
        <GradientStop Color="#FF000000" Offset="0.5"/>
        <GradientStop Color="#FF332A15" Offset="1"/>
    </LinearGradientBrush>

 

Usage Syntax:

Its very simple just use above lines in App.xaml under <Application.Resources> and then you can use them any where in your project

<Rectangle ... Fill="{StaticResource DarkBrown}"/>

Download:

XAML Resource (0.5 KB) Download ZIP