Sunday, August 21, 2016

Facade Pattern


Facade pattern provides simpler way to users to access complex subsystems. Facade pattern falls under structural pattern of GOF (Gang of Four) patterns.

When to use –


Facade pattern can be used when you have to deal with multiple classes having complex and difficult logic. Facade class acts as “wrapper” class and provides easy to understand and simple to use interface to client. Facade object decouples the subsystems from the client. Client doesn’t have information about how subsystems objects are created and its methods are called in Facade class. Facade class provides client a simpler way to access subsystems. Facade pattern can also be used when you need entry point to multiple complex subsystems.

Facade pattern can also be ideal choice when you are dealing with multiple legacy systems and you can’t change code of legacy systems due to code unavailability or multiple systems are impacted by code change.

Major components of Facade Pattern –


Facade – This is a class and acts as wrapper for delegating client request to respective subsystems.
Subsystems – This are subsystem classes which contains functionality that client wants.

There are so many real world example available for Facade pattern but most common example is Reception counter or “May I Help you” counter at any company or bank. So client just need to contact to reception counter and he/she will be redirected to respective department to get his/her work done. See below example of Facade pattern.

Code –
//subsystem-1
public class SavingsAccount
{
    public void OpenNewAccount(string name)
    {
        Console.WriteLine(string.Format("{0}, welcome to savings account department", name));
    }
}
//subsystem-2
public class CreditCard
{
    public void ApplyCreditCard(string name)
    {
        Console.WriteLine(string.Format("{0}, welcome to credit card department.", name));
    }
}
//subsystem-3
public class PersonalLoan
{
    public void GetPersonalLoan(string name)
    {
        Console.WriteLine(string.Format("{0}, welcome to personal loan department", name));
    }
}
//Facade
public class Reception
{
    private string Name;
    private SavingsAccount savingsaccount = new SavingsAccount();
    private CreditCard creditCard = new CreditCard();
    private PersonalLoan personalLoan = new PersonalLoan();
    public Reception(string name)
    {
        Name = name;
    }
    public void GetPersonalLoan()
    {
        personalLoan.GetPersonalLoan(Name);
    }
    public void ApplyForCreditCard()
    {
        creditCard.ApplyCreditCard(Name);
    }
    public void OpenSavingsAccount()
    {
        savingsaccount.OpenNewAccount(Name);
    }
}
//client
class Program
{
    static void Main(string[] args)
    {
        Reception reception = new Reception("Mitesh");
        reception.OpenSavingsAccount();
        reception.ApplyForCreditCard();
        reception.GetPersonalLoan();

        Console.ReadLine();
    }
}

Output –




As you can see in above example, Reception class acts as Facade (wrapper) class which is entry point for client to connect to multiple subsystems for his/her different types of need like opening savings account, get personal loan, apply for credit card etc.

I hope this article helps you to know more about Facade Pattern. Please leave your feedback in comments section below.


References –

See Also –


Saturday, August 13, 2016

Adorners in WPF


Adorner is a special framework element which is bound to UIElement. You can check WPF Class Hierarchy for more about WPF controls. Adorners is the way to extend controls via adding extra visual functionality.

WPF internally uses adorners in validating controls, you must have seen red border on controls whose validation failed. The red border is adorner layer which is placed on top of the control. You can check my article How to validate data in WPF to know more about validations.

Adorners are bound to UIElement and placed top of it and independent of rendering of UIElement. You can add additional functionalities of UIElement like resize, move, rotate etc via adding Adorner layer to UIElement. Adorners are visual decoration to decorate UIElement.

See below example which uses adorner to select/resize UIElement on canvas.

XAML
<Window x:Class="AdornerExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AdornerExample"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Canvas Name="myCanvas">
        <Button Height="50" Width="150" Content="Click Me!"
                Canvas.Left="50" Canvas.Top="50"
                Name="myButton" />
        <TextBox Height="25" Width="120"
                 Text="TextBox"
                 Canvas.Top="200" Canvas.Left="100" />

    </Canvas>
</Window>

Code –  
Custom adorner for decorating UIElement
public class BorderAdorner : Adorner
{
    //use thumb for resizing elements
    Thumb topLeft, topRight, bottomLeft, bottomRight;
    //visual child collection for adorner
    VisualCollection visualChilderns;

    public BorderAdorner(UIElement element) : base(element)
    {
        visualChilderns = new VisualCollection(this);
           
        //adding thumbs for drawing adorner rectangle and setting cursor
        BuildAdornerCorners(ref topLeft, Cursors.SizeNWSE);
        BuildAdornerCorners(ref topRight, Cursors.SizeNESW);
        BuildAdornerCorners(ref bottomLeft, Cursors.SizeNESW);
        BuildAdornerCorners(ref bottomRight, Cursors.SizeNWSE);

        //registering drag delta events for thumb drag movement
        topLeft.DragDelta += TopLeft_DragDelta;
        topRight.DragDelta += TopRight_DragDelta;
        bottomLeft.DragDelta += BottomLeft_DragDelta;
        bottomRight.DragDelta += BottomRight_DragDelta;
    }

    private void BottomRight_DragDelta(object sender, DragDeltaEventArgs e)
    {
        FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
        Thumb bottomRightCorner = sender as Thumb;
        //setting new height and width after drag
        if (adornedElement != null && bottomRightCorner != null)
        {
            EnforceSize(adornedElement);

            double oldWidth = adornedElement.Width;
            double oldHeight = adornedElement.Height;

            double newWidth = Math.Max(adornedElement.Width + e.HorizontalChange, bottomRightCorner.DesiredSize.Width);
            double newHeight = Math.Max(e.VerticalChange + adornedElement.Height , bottomRightCorner.DesiredSize.Height);
               
            adornedElement.Width = newWidth;
            adornedElement.Height = newHeight;
        }
    }

    private void TopRight_DragDelta(object sender, DragDeltaEventArgs e)
    {
        FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
        Thumb topRightCorner = sender as Thumb;
        //setting new height, width and canvas top after drag
        if (adornedElement != null && topRightCorner != null)
        {
            EnforceSize(adornedElement);

            double oldWidth = adornedElement.Width;
            double oldHeight = adornedElement.Height;

            double newWidth = Math.Max(adornedElement.Width + e.HorizontalChange, topRightCorner.DesiredSize.Width);
            double newHeight = Math.Max(adornedElement.Height - e.VerticalChange, topRightCorner.DesiredSize.Height);
            adornedElement.Width = newWidth;

            double oldTop = Canvas.GetTop(adornedElement);
            double newTop = oldTop - (newHeight - oldHeight);
            adornedElement.Height = newHeight;
            Canvas.SetTop(adornedElement, newTop);
        }
    }

    private void TopLeft_DragDelta(object sender, DragDeltaEventArgs e)
    {
        FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
        Thumb topLeftCorner = sender as Thumb;
        //setting new height, width and canvas top, left after drag
        if (adornedElement != null && topLeftCorner != null)
        {
            EnforceSize(adornedElement);

            double oldWidth = adornedElement.Width;
            double oldHeight = adornedElement.Height;

            double newWidth = Math.Max(adornedElement.Width - e.HorizontalChange, topLeftCorner.DesiredSize.Width);
            double newHeight = Math.Max(adornedElement.Height - e.VerticalChange, topLeftCorner.DesiredSize.Height);

            double oldLeft = Canvas.GetLeft(adornedElement);
            double newLeft = oldLeft - (newWidth - oldWidth);
            adornedElement.Width = newWidth;
            Canvas.SetLeft(adornedElement, newLeft);

            double oldTop = Canvas.GetTop(adornedElement);
            double newTop = oldTop - (newHeight - oldHeight);
            adornedElement.Height = newHeight;
            Canvas.SetTop(adornedElement, newTop);
        }
    }

    private void BottomLeft_DragDelta(object sender, DragDeltaEventArgs e)
    {
        FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
        Thumb topRightCorner = sender as Thumb;
        //setting new height, width and canvas left after drag
        if (adornedElement != null && topRightCorner != null)
        {
            EnforceSize(adornedElement);

            double oldWidth = adornedElement.Width;
            double oldHeight = adornedElement.Height;

            double newWidth = Math.Max(adornedElement.Width - e.HorizontalChange, topRightCorner.DesiredSize.Width);
            double newHeight = Math.Max(adornedElement.Height + e.VerticalChange, topRightCorner.DesiredSize.Height);

            double oldLeft = Canvas.GetLeft(adornedElement);
            double newLeft = oldLeft - (newWidth - oldWidth);
            adornedElement.Width = newWidth;
            Canvas.SetLeft(adornedElement, newLeft);

            adornedElement.Height = newHeight;
        }
    }
       
    public void BuildAdornerCorners(ref Thumb cornerThumb, Cursor customizedCursors)
    {
        //adding new thumbs for adorner to visual childern collection
        if (cornerThumb != null) return;
        cornerThumb = new Thumb() { Cursor = customizedCursors, Height = 10, Width = 10, Opacity = 0.5, Background = new SolidColorBrush(Colors.Red) };
        visualChilderns.Add(cornerThumb);
    }
       
    public void EnforceSize(FrameworkElement element)
    {
        if (element.Width.Equals(Double.NaN))
            element.Width = element.DesiredSize.Width;
        if (element.Height.Equals(Double.NaN))
            element.Height = element.DesiredSize.Height;
           
        //enforce size of element not exceeding to it's parent element size
        FrameworkElement parent = element.Parent as FrameworkElement;

        if (parent != null)
        {
            element.MaxHeight = parent.ActualHeight;
            element.MaxWidth = parent.ActualWidth;
        }
    }
       
    protected override Size ArrangeOverride(Size finalSize)
    {
        base.ArrangeOverride(finalSize);

        double desireWidth = AdornedElement.DesiredSize.Width;
        double desireHeight = AdornedElement.DesiredSize.Height;

        double adornerWidth = this.DesiredSize.Width;
        double adornerHeight = this.DesiredSize.Height;
           
        //arranging thumbs
        topLeft.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
        topRight.Arrange(new Rect(desireWidth - adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
        bottomLeft.Arrange(new Rect(-adornerWidth / 2, desireHeight - adornerHeight / 2, adornerWidth, adornerHeight));
        bottomRight.Arrange(new Rect(desireWidth - adornerWidth / 2, desireHeight - adornerHeight / 2, adornerWidth, adornerHeight));

        return finalSize;
    }
    protected override int VisualChildrenCount { get { return visualChilderns.Count; } }
    protected override Visual GetVisualChild(int index) { return visualChilderns[index]; }
    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);
    }
}


MainWindow code -
public partial class MainWindow : Window
{
    bool isDown, isDragging, isSelected;
    UIElement selectedElement = null;
    double originalLeft, originalTop;
    Point startPoint;

    AdornerLayer adornerLayer;

    public MainWindow()
    {
        InitializeComponent();
        this.Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        //registering mouse events
        this.MouseLeftButtonDown += MainWindow_MouseLeftButtonDown;
        this.MouseLeftButtonUp += MainWindow_MouseLeftButtonUp;
        this.MouseMove += MainWindow_MouseMove;
        this.MouseLeave += MainWindow_MouseLeave;

        myCanvas.PreviewMouseLeftButtonDown += MyCanvas_PreviewMouseLeftButtonDown;
        myCanvas.PreviewMouseLeftButtonUp += MyCanvas_PreviewMouseLeftButtonUp;
    }

    private void StopDragging()
    {
        if (isDown)
        {
            isDown = isDragging = false;
        }
    }


    private void MyCanvas_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        StopDragging();
        e.Handled = true;
    }

    private void MyCanvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        //removing selected element
        if (isSelected)
        {
            isSelected = false;
            if (selectedElement != null)
            {
                adornerLayer.Remove(adornerLayer.GetAdorners(selectedElement)[0]);
                selectedElement = null;
            }
        }

        // select element if any element is clicked other then canvas
        if (e.Source != myCanvas)
        {
            isDown = true;
            startPoint = e.GetPosition(myCanvas);

            selectedElement = e.Source as UIElement;

            originalLeft = Canvas.GetLeft(selectedElement);
            originalTop = Canvas.GetTop(selectedElement);

            //adding adorner on selected element
            adornerLayer = AdornerLayer.GetAdornerLayer(selectedElement);
            adornerLayer.Add(new BorderAdorner(selectedElement));
            isSelected = true;
            e.Handled = true;
        }
    }

    private void MainWindow_MouseMove(object sender, MouseEventArgs e)
    {
        //handling mouse move event and setting canvas top and left value based on mouse movement
        if (isDown)
        {
            if ((!isDragging) &&
                ((Math.Abs(e.GetPosition(myCanvas).X - startPoint.X) > SystemParameters.MinimumHorizontalDragDistance) ||
                (Math.Abs(e.GetPosition(myCanvas).Y - startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)))
                isDragging = true;

            if (isDragging)
            {
                Point position = Mouse.GetPosition(myCanvas);
                Canvas.SetTop(selectedElement, position.Y - (startPoint.Y - originalTop));
                Canvas.SetLeft(selectedElement, position.X - (startPoint.X - originalLeft));
            }
        }
    }

    private void MainWindow_MouseLeave(object sender, MouseEventArgs e)
    {
        //stop dragging on mouse leave
        StopDragging();
        e.Handled = true;
    }

    private void MainWindow_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        //stop dragging on mouse left button up
        StopDragging();
        e.Handled = true;
    }

    private void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        //remove selected element on mouse down
        if (isSelected)
        {
            isSelected = false;
            if (selectedElement != null)
            {
                adornerLayer.Remove(adornerLayer.GetAdorners(selectedElement)[0]);
                selectedElement = null;
            }
        }
    }
}


Output –






As you can see in above example, two controls Button and Textbox added to Canvas. When user click on any control, the red corners will appear to control. This red corners are added as an adorner to UIElement or control like button or textbox etc. Now you can resize UIElement via resizing red corners. You can move UIElement via Mouse Drag. So this way you can add additional functionality to UIElement visually via adorner.

To create custom adorner, you need to create class deriving from Adorner class. Thumb is special class derived from FrameworkElement. Thumb class can be used to draw rectangle or other shape for Adorner. In above example you can see Red rectangle at each corner of selected UIElement, is created using Thumb class. Thumb class has event called DragDelta. You need to handle DragDelta event for each thumb you create. Once you create Thumbs for adorner you need to add all Thumbs to VisualCollection.

In MainWondow file, you need to handle different window mouse events like MouseMove, MouseLeave, MouseLeftButtonUp, MouseLeftButtonDown etc to handle drag/drop and mouse move event of selected element. Also you need write code to select UIElement and apply adorner to selected element. This is handled in MyCanvas_PreviewMouseLeftButtonDown event of Canvas in above example.

I hope this article helps you to understand more about Adorners. Please give your feedback in comments below.


References –

See Also –