Silverlight: Search box

A simple search box for Silverlight.
it got a watermark, a search button, and a “clear search” button.

pretty simple and basic.

Here is the demo
and the code is on GitHub, you can browse (and get) it here.

Silverlight: close Popup on click outside

This was a hard one…
One of the things that is very much missing in Silverlight is closing a Popup upon clicking outside of it.
this is implemented as StaysOpen (true/false) in WPF.
but is very much missing in Silverlight Popup.

i wanted to make it as simple as possible, without any dependencies on other dll, and support binding changes.
so an attached property was the way to go.

lots of thanks to Vladi (koganvladimir at yahoo dot com) on helping here.

to use it simply add the attached property to your Popup, when the value is set to False the popup will be closed upon clicking outside.
here are two common use case examples:

<Popup helpers:PopupHelper.StaysOpen="False">
<Popup helpers:PopupHelper.StaysOpen="{Binding SomeChangingBool}">

and here is the PopupHelper.cs class:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace Helpers
{
    public class PopupHelper
    {

        public static bool GetStaysOpen(DependencyObject obj)
        {
            return (bool)obj.GetValue(StaysOpenProperty);
        }

        public static void SetStaysOpen(DependencyObject obj, bool value)
        {
            obj.SetValue(StaysOpenProperty, value);
        }

        public static readonly DependencyProperty StaysOpenProperty =
            DependencyProperty.RegisterAttached("StaysOpen", typeof(bool), typeof(PopupHelper),
                                                new PropertyMetadata(true, StaysOpenChanged));

        private static void StaysOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var pop = d as Popup;
            if (pop == null) return;

            // this is the only way i could find to tell (or wait) for after loaded.
            if (pop.Child == null)
            {
                pop.Loaded += PopOnLoaded;
            }
            else
            {
                UpdateStaysOpen(pop, (bool)e.NewValue);
            }
        }

        private static void PopOnLoaded(object sender, RoutedEventArgs routedEventArgs)
        {
            var pop = sender as Popup;
            if (pop == null) return;
            pop.Loaded -= PopOnLoaded;
            UpdateStaysOpen(pop, (bool)pop.GetValue(StaysOpenProperty));
        }

        private static void UpdateStaysOpen(Popup popup, bool stayOpen)
        {
            var blocker = GetBlocker(popup);
            if (blocker == null)
            {
                SetBlockerLayer(popup);
                blocker = GetBlocker(popup);
            }
            blocker.IsHitTestVisible = !stayOpen;
        }

        private static Canvas GetBlocker(Popup pop)
        {
            var elementPopupChildCanvas = pop.Child as FrameworkElement;
            var blocker = VisualTreeHelper.GetChild(elementPopupChildCanvas, 0) as FrameworkElement;
            Canvas retVal;
            if ((retVal = blocker as Canvas) != null && blocker.Tag.ToString() == "ElementPopupBlocker")
            {
                return retVal;
            }
            return null;
        }

        private static void SetBlockerLayer(Popup popup)
        {
            var popupChild = popup.Child as FrameworkElement;
            if (popupChild == null) return;
            var blocker = new Canvas { Background = new SolidColorBrush(Colors.Gray), Tag = "ElementPopupBlocker" };
            blocker.MouseLeftButtonDown += delegate { popup.IsOpen = false; };
            var elementPopupChildCanvas = new Canvas();
            popup.Child = elementPopupChildCanvas;
            elementPopupChildCanvas.Children.Add(blocker);
            elementPopupChildCanvas.Children.Add(popupChild);

            popupChild.HorizontalAlignment = HorizontalAlignment.Left;
            popupChild.VerticalAlignment = VerticalAlignment.Top;
            Canvas.SetLeft(popupChild, popup.HorizontalOffset);
            Canvas.SetTop(popupChild, popup.VerticalOffset);
            popup.HorizontalOffset = 0.0;
            popup.VerticalOffset = 0.0;

            popup.LayoutUpdated += delegate { Arrange(popup); };
        }

        private static void Arrange(Popup popup)
        {
            if (!popup.IsOpen) return;
            var elementPopupChildCanvas = popup.Child;
            if (elementPopupChildCanvas == null) return;
            var blocker = VisualTreeHelper.GetChild(elementPopupChildCanvas, 0) as Canvas;
            var popupChild = VisualTreeHelper.GetChild(elementPopupChildCanvas, 1) as FrameworkElement;
            if (blocker == null || popupChild == null) return;

            var width = Application.Current.Host.Content.ActualWidth;
            var height = Application.Current.Host.Content.ActualHeight;
            if (height < 50.0 || width < 50.0)
                return;

            var generalTransform = popup.TransformToVisual(null);
            var point1 = new Point(0.0, 0.0);
            var point2 = new Point(1.0, 0.0);
            var point3 = new Point(0.0, 1.0);
            var point4 = generalTransform.Transform(point1);
            var point5 = generalTransform.Transform(point2);
            var point6 = generalTransform.Transform(point3);

            var identity = Matrix.Identity;
            identity.M11 = point5.X - point4.X;
            identity.M12 = point5.Y - point4.Y;
            identity.M21 = point6.X - point4.X;
            identity.M22 = point6.Y - point4.Y;
            identity.OffsetX = point4.X;
            identity.OffsetY = point4.Y;
            var num = identity.M11 * identity.M22 - identity.M12 * identity.M21;
            var matrix = identity;
            identity.M11 = matrix.M22 / num;
            identity.M12 = -1.0 * matrix.M12 / num;
            identity.M21 = -1.0 * matrix.M21 / num;
            identity.M22 = matrix.M11 / num;
            identity.OffsetX = (matrix.OffsetY * matrix.M21 - matrix.OffsetX * matrix.M22) / num;
            identity.OffsetY = (matrix.OffsetX * matrix.M12 - matrix.OffsetY * matrix.M11) / num;

            blocker.Width = width;
            blocker.Height = height;
            blocker.RenderTransform = new MatrixTransform { Matrix = identity };
        }
    }
}

Zoom manager – A Visual Studio Extension

This extension makes the zoom level consistent in all the editors, and saves it for later to use as your default zoom level.
You don’t have to manage the zoom any more, this extension does it for you.
(it was heavily inspired by the Presentation Zoom extension, which lack the feature of saving)

here it is on the Visual Studio gallery: Zoom Manager

you can also get within your Visual Studio –> Tools –> Extension Manager.

WPF MVVM project template

This extension will add a Visual Studio 2010 project template to create a WPF client application with MVVM pattern project structure.

(after installing the .vsix you’ll need to restart Visual Studio).

the new project template can be found under: File -> New -> Project -> C# templates.
it is called “WPF MVVM Application”.

the new project have an MVVM folders and classes structure with some randomly generated data and a simple view.

download from HERE

C# random helper class

Very often i make an ‘offline’ application in order to work faster without the need to compile the whole big-mama application.
as it name suggest an ‘offline’ app does not have a database to work with so i need to mock some data.
with some code borrowed from this blog post the below C# random helper class can be used in any application.
(if you have something to add drop a comment)

using System;
using System.Text;
using System.Windows.Media;

namespace WpfApplication1.Helper
{
    public static class RandomHelper
    {
        private static Random randomSeed = new Random();

        /// <summary>
        /// Generates a random string with the given length
        /// </summary>
        /// <param name="size">Size of the string</param>
        /// <param name="lowerCase">If true, generate lowercase string</param>
        /// <returns>Random string</returns>
        public static string RandomString(int size, bool lowerCase)
        {
            // StringBuilder is faster than using strings (+=)
            StringBuilder RandStr = new StringBuilder(size);

            // Ascii start position (65 = A / 97 = a)
            int Start = (lowerCase) ? 97 : 65;

            // Add random chars
            for (int i = 0; i < size; i++)
                RandStr.Append((char)(26 * randomSeed.NextDouble() + Start));

            return RandStr.ToString();
        }

        public static int RandomInt(int min, int max)
        {
            return randomSeed.Next(min, max);
        }

        public static double RandomDouble()
        {
            return randomSeed.NextDouble();
        }

        public static double RandomNumber(int min, int max, int digits)
        {
            return Math.Round(randomSeed.Next(min, max - 1) + randomSeed.NextDouble(), digits);
        }

        public static bool RandomBool()
        {
            return (randomSeed.NextDouble() > 0.5);
        }

        public static DateTime RandomDate()
        {
            return RandomDate(new DateTime(1900, 1, 1), DateTime.Now);
        }

        public static DateTime RandomDate(DateTime from, DateTime to)
        {
            TimeSpan range = new TimeSpan(to.Ticks - from.Ticks);
            return from + new TimeSpan((long)(range.Ticks * randomSeed.NextDouble()));
        }

        public static Color RandomColor()
        {
            return Color.FromRgb((byte)randomSeed.Next(255), (byte)randomSeed.Next(255), (byte)randomSeed.Next(255));
        }

    }
}

Resource Viewer V2.0

Version 2.0 is out!

Read the first post and full description: Resource Viewer – A Visual Studio Extension

New in V2.0:

  • Added support for additional resource types – now you can also view your Brush(es):DrwaingBrush,  SolidColorBrush, Gradients, etc.
  • Details view.
  • The code is now constructed better.

The whole project and source code is maintained here: 
http://resourceviewer.codeplex.com/

It is also hosted in the Visual Studio gallery, here: Resource Viewer

Resource Viewer – A Visual Studio Extension

Simply put the “resource viewer extension” enables you to visually view your ResourceDictionary.

To open it go to: View – Other Windows – Resource Viewer.

When working with WPF/Silverlight you put your reusable resources in a common ResourceDictionary, those resources might be of type Style, SolidColorBrush, DrawingBrush, BitmapImage and more. The problems starts when you have that ResourceDictionary you have no way to see how your resources look like, making the work process (of both the developer who maintains this dictionary and the one who uses it) clumsy and based on guessing.

This extension comes to solve those problems!

With the “Resource viewer “ extension you can open any ResourceDictionary and actually see how your resources look like – your icons, brushes, etc. are all being visualized right inside Visual Studio.

Than when you’ve found the resource you’ve been after you can “inject” it into a file that is opened within Visual Studio.

Features:

  • A Visual Studio 2010 extension – meaning it integrates with VS api and behave like any other window (docking, floating etc.)
  • Open any XAML ResourceDictionary file on your computer – simply browse to it.
  • When you open the viewer it automatically opens the last opened file.
  • Most recently used files list.
  • Refresh button to reload the opened file.
  • The opened file is being watched for changes, if a change is made you’ll be notified.
  • Zoom slider and zoom presets.
  • Search box.
  • Inject the selected item’s x:Key into an opened document by double-click on an item or pressing the “Inject” button.
  • Inject prefix and suffix strings. Those are saved and persisted.

Future plans:

  • Current version handles only DrawingImage, add handling for more resource types.
  • Add handling for Merged Dictionaries.
  • Add a detailed view for the selected item.
  • More…

If you are willing to help in any way please drop me a note.

The whole project and source code is maintained here: 
http://resourceviewer.codeplex.com/

It is also hosted in the Visual Studio gallery, here: Resource Viewer

Follow

Get every new post delivered to your Inbox.