Why you should learn Delegates?


What everyone should learn while start writing code is the Basic Fundamentals, which most of them doesn’t do (myself among the one). Instead they go behind the attractive features, which is easy to learn and understand. In short run, you’ll win. But, in the long run, you’ll fail or you’ll end up using more lines of codes than required or you’ll write the most ugliest code.

I’m no different and I end up writing bloody-ugly code, due to my ignorance, delay and laziness to learn the fundamentals.

Few months back, I’m playing with user-controls in Silverlight 4, in which I want to pass data from one user control to another. And, delegate is the most perfect and standard way to do that.

The Ugly side of Ignorance – Object Passing

My situation was like this, I have a main page (say, MainPage.xaml) in which I’m loading a User Control (say, DocumentDetails.xaml). The MainPage.xaml contains a Label control which displays the total number of documents loaded in the  DocumentDetails.xaml.

Something like this:

WithoutDelegate

What I’d done is, in my DocumentDetails.xaml, I created a property named DocumentCount whose type is Label. The purpose of this property is to keep a reference of the Label in the MainPage.xaml, so that any update to the property: DocumentCount will update the original Label content in the MainPage.xaml.

Here goes my (ugly) code:

Documents.cs (Custom Class)

/*** Documents.cs ***/
 
public class Documents
    {
        public int Id { get; set; }
 
        public string Name { get; set; }
 
        public string Type { get; set; }
    }

 

DocumentDetails.xaml (Design)

<!-- DocumentDetails.xaml (Design) -->
<Grid x:Name="LayoutRoot" Margin="10" Height="Auto" Width="Auto" 
HorizontalAlignment="Center" Background="White">
        <sdk:DataGrid AutoGenerateColumns="False" 
                      Height="Auto" 
                      Margin="10"
                      RowHeight="40"
                      HorizontalAlignment="Left" 
                      Name="dgDocuments" 
                      VerticalAlignment="Top" 
                      Width="Auto">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTemplateColumn Header="Id" Width="50">
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Id}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
                <sdk:DataGridTemplateColumn Header="Name" Width="150">
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Name}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
                <sdk:DataGridTemplateColumn Header="Type" Width="150">
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Type}" />
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
    </Grid>

 

DocumentDetails.xaml.cs (Code-Behind)

/*** DocumentDetails.xaml.cs ***/
public partial class DocumentDetails : UserControl
    {
        /// <summary>
        /// Reference of Label object from MainPage.xml
        /// </summary>
        public Label DocumentCount { get; set; }
 
        /// <summary>
        /// Constructor
        /// </summary>
        public DocumentDetails()
        {
            InitializeComponent();
        }
 
        /// <summary>
        /// User Control Loaded
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            List<Documents> olstDocs = new List<Documents>() { 
                new Documents(){ Id = 1, Name = "Name 1", Type = "Type 1" },
                new Documents(){ Id = 2, Name = "Name 2", Type = "Type 2" },
                new Documents(){ Id = 3, Name = "Name 3", Type = "Type 3" },
                new Documents(){ Id = 4, Name = "Name 4", Type = "Type 4" },
                new Documents(){ Id = 5, Name = "Name 5", Type = "Type 5" }
            };
 
            // Set Count
            DocumentCount.Content = "Total Docs: " + olstDocs.Count;
 
            // Bind Data
            dgDocuments.ItemsSource = olstDocs;
        }
    }


MainPage.xaml (Design)

<!-- MainPage.xaml (Designer) -->
<Grid x:Name="LayoutRoot" Background="White" HorizontalAlignment="Center">
        <Grid.RowDefinitions>
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        
        <!-- Count -->
        <sdk:Label Grid.Row="0" 
                   Grid.Column="0" 
                   Name="lblCount" 
                   Content="Total Docs: " 
                   VerticalAlignment="Center" 
                   HorizontalAlignment="Left" 
                   VerticalContentAlignment="Center" 
                   Width="120" 
                   FontSize="12" />
 
        <!-- Load UserControl -->
        <Button Content="Load Documents" 
                Grid.Row="1" 
                Grid.Column="0"
                Height="23" 
                HorizontalAlignment="Left" 
                Name="btnLoadDocs" 
                VerticalAlignment="Center" 
                Click="btnLoadDocs_Click"
                Width="150" />
 
        <!-- Container -->
        <StackPanel Grid.Row="2" 
                    Grid.Column="0" 
                    x:Name="stkpnlContainer" 
                    Height="Auto" 
                    Width="400" 
                    HorizontalAlignment="Left" 
                    Orientation="Vertical" 
                    Background="Gray">
        </StackPanel>
        
    </Grid>

 

MainPage.xaml.cs (Code-Behind)

/*** MainPage.xaml.cs (Code-Behind) ***/
public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }
 
        /// <summary>
        /// Load Document Control
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLoadDocs_Click(object sender, RoutedEventArgs e)
        {
            DocumentDetails oDocDetails = new DocumentDetails();
            // Pass the Label reference
            oDocDetails.DocumentCount = lblCount;
 
            stkpnlContainer.Children.Clear();
            stkpnlContainer.Children.Add(oDocDetails);
        }
    }

 

So what’s the problem with this? It’ll work fine. Correct?

Well the problem is, I’m passing the object reference itself. And the situation is more worse, if I want to update more Controls in my parent form (here MainPage.xaml), which makes me to pass more control reference, in turn making it ugly.

The Powerful side of Fundamentals – Delegates

Well…Well…Well… There is a powerful solution to handle this called Delegates. Simply, Delegate is function pointer, the most common definition that you’ll hear, if you ask a good amount of developers! Another definition? They’ll scratch their head.

Windows and Web development relies on event-driven mechanism. When you perform an Action (Event, say Click), you need a Method/Procedure (Event Handler) to be invoked as part of the action, to perform an operation. And, Delegate acts as a conduit between Event Source and Event Handler methods. The delegate carries the information about the Event to the Event Handler.

In our situation, you can handle the total count displaying in the MainPage.xaml by;

  1. Declaring delegate & event in the DocumentsDisplay.xaml
  2. Registering event in the MainPage.xaml & defining the event-handler method to handle the raised event
  3. Here goes the code:
    DocumentDetails.xaml.cs
    /*** DocumentDetails.xaml.cs ***/
    public partial class DocumentDetails : UserControl
        {
            /// <summary>
            /// Delegate
            /// </summary>
            /// <param name="count"></param>
            public delegate void TotalCountHandler(int count);
     
            /// <summary>
            /// Event to fire the "Total Count" value
            /// </summary>
            public event TotalCountHandler Count;
     
            /// <summary>
            /// Constructor
            /// </summary>
            public DocumentDetails()
            {
                InitializeComponent();
            }
     
            /// <summary>
            /// User Control Loaded
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void UserControl_Loaded(object sender, RoutedEventArgs e)
            {
                List<Documents> olstDocs = new List<Documents>() { 
                    new Documents(){ Id = 1, Name = "Name 1", Type = "Type 1" },
                    new Documents(){ Id = 2, Name = "Name 2", Type = "Type 2" },
                    new Documents(){ Id = 3, Name = "Name 3", Type = "Type 3" },
                    new Documents(){ Id = 4, Name = "Name 4", Type = "Type 4" },
                    new Documents(){ Id = 5, Name = "Name 5", Type = "Type 5" }
                };
     
                // Set Count
     
                // Check whether event is registered or not
                if (Count != null)
                {
                    // Fire Event
                    Count(olstDocs.Count);
                }
     
                // Bind Data
                dgDocuments.ItemsSource = olstDocs;
            }
        }
    MainPage.xaml.cs
    /*** MainPage.xaml.cs ***/
    public partial class MainPage : UserControl
        {
            DocumentDetails oDocDetails;
     
            /// <summary>
            /// Constructor
            /// </summary>
            public MainPage()
            {
                InitializeComponent();
            }
     
            /// <summary>
            /// Load Document Control
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnLoadDocs_Click(object sender, RoutedEventArgs e)
            {
                oDocDetails = new DocumentDetails();
                
                // Register Event
                oDocDetails.Count += new DocumentDetails.TotalCountHandler(oDocDetails_Count);
     
                stkpnlContainer.Children.Clear();
                stkpnlContainer.Children.Add(oDocDetails);
            }
     
            /// <summary>
            /// EventHandler method that sets the Total Count
            /// </summary>
            /// <param name="count"></param>
            void oDocDetails_Count(int count)
            {
                lblCount.Content = "Total Docs: " + count;
     
                // Remove Event
                oDocDetails.Count -= oDocDetails_Count;
            }
        }

Preview

Delegate

Download Source

Hope this helped. Thanks!

Error while adding Windows DLL to Silverlight


I guess, this month is really buggy for me. Encountered a lot of errors and bugs during the development and my recent posts reflects the same. Because, I’m pushed through a lot of new Technologies during these days. It’s not that lot of new technologies are released during these days. But, the fact is - I’m a late adopter of Technology.

This time, I’s integrating a Silverlight Application into an existing 3-tier architecture project. Since, the idea of layer reuse exists, I used the same layers for building the Silverlight Application. The business later for my project is a Windows DLL and I referred the DLL into my Silverlight application for making reusing of layer practical.

Bhoom!!! I’s shocked with an error:

You can only add project references to other Silverlight project in the solution.

SL_WinDll_addingError

Upon close investigation, its clear that the CLR for both desktop and Silverlight uses 2 different engine. And that is the reason, why I cannot refer my Windows DLL into the Silverlight application.

Here you have 2 options:

  1. Use a Silverlight Class Library
  2. Use WCF Service.

I’ll ask you to go with WCF.

And please note. not every Windows namespaces are available in Silverlight, say you won’t get System.Data namespace and few others. This is done to keep the Silverlight plugin as simple and light-weight as possible. Might there be any future enhancements. But as of now, not everything that is available in Windows DLL is not available in Silverlight. So before you jump on to Silverlight and start developing the Rich application, please please please take care of the available data retrieval options.

Hope this helps.

Thanks and Merry X’Mas.