Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Custom Silverlight TextBox with contextmenu (Cut, Copy, Paste and Delete)

0.00/5 (No votes)
30 Mar 2010 2  
This article describes a basic functionality of textbox with cut, copy, paste and delete using context menu which might be helpful to enrich user experience and assist developers.

Introduction

  1. Silverlight 4 (Beta)
  2. VS2010 (Beta)
  3. .NET Framework 4.0 (Beta)

This article describes a basic functionality of textbox with cut, copy, paste and delete using context menu which might be helpful to enrich user experience and assist developers.
By default, Silverlight does not provide a context menu.
first.JPG
Second.JPG

This article is an attempt to solve the interesting but important problem in Silverlight textbox.
Also works as both plug-in Silverlight and out of browser..

Background

Silverlight 4 now enables MouseRightButtonUp/Down events to attach and handle. This allows the developer to take control over what he/she likes to do when those events occur (for example, context style menus functionality within the application).

Third.JPG
However, context menu is not provided by Silverlight because it requires to be user initiated called by an application in response to user input. More details can be found at Security Overview of Silverlight 4.

Using the Code

<CustomPlaceHolder> Class

Public abstract class CustomPlaceHolder
{
        private Point _location;
        private bool _isShowing;
        private Popup _popup;
        private Grid _grid;
        private FrameworkElement _content;

        public void Show(Point location)
        {
            if (_isShowing)
                throw new InvalidOperationException();

            _isShowing = true;
            _location = location;
            DisplayPopup();
            _popup.IsOpen = true;
        }

        public void Close()
        {
            _isShowing = false;
            if (_popup != null)
                _popup.IsOpen = false;
        }

        private void DisplayPopup()
        {
            _popup = new Popup();
            _grid = new Grid();
            _popup.Child = _grid;
            _content = GetContent();
            _content.HorizontalAlignment = HorizontalAlignment.Left;
            _content.VerticalAlignment = VerticalAlignment.Top;
            _content.Margin = new Thickness(_location.X, _location.Y, 0, 0);
            _grid.Children.Add(_content);
        }

        #region Abstract and Virtual
        protected abstract FrameworkElement GetContent();
        protected virtual void OnClickOutside() { }
        #endregion //Abstract and  Virtual           //

This abstract base class is used to create a popup menu irrespective of what kind of controls are going to be placed inside. This just acts as a placeholder or could be called a container.

<CustomContextMenu : CustomPlaceHolder> Class

Public abstract class CustomContextMenu : CustomPlaceHolder
{
        protected override FrameworkElement GetContent()
        {
            Grid grid = new Grid()
            {
                Width = 100,
                Height = 100
            };
            Border border = new Border()
            {
                BorderBrush = new SolidColorBrush(Colors.Black),
                BorderThickness = new Thickness(1),
                Background = new SolidColorBrush(Colors.LightGray)
            };
            _options = new ListBox();
            AddToListBox();
            grid.Children.Add(_options);
            return grid;
        }

        private void AddToListBox()
        {
            TextBlock cut = new TextBlock()
            {
                Text = "Cut",
                Width = 90
            };
            cut.MouseLeftButtonDown += 
		new System.Windows.Input.MouseButtonEventHandler
			(cut_MouseLeftButtonDown);
            TextBlock copy = new TextBlock()
            {
                Text = "Copy",
                Width = 90
            };
            copy.MouseLeftButtonDown += 
		new System.Windows.Input.MouseButtonEventHandler
			(copy_MouseLeftButtonDown);
            TextBlock paste = new TextBlock()
            {
                Text = "Paste",
                Width = 90
            };
            paste.MouseLeftButtonDown += 
		new System.Windows.Input.MouseButtonEventHandler
			(paste_MouseLeftButtonDown);
            TextBlock delete = new TextBlock()
            {
                Text = "Delete",
                Width = 90
            };
            delete.MouseLeftButtonDown += 
		new System.Windows.Input.MouseButtonEventHandler
			(delete_MouseLeftButtonDown);
            if (string.IsNullOrEmpty(_textBox.SelectedText))
            {
                cut.Foreground = new SolidColorBrush(Colors.Gray);
                copy.Foreground = new SolidColorBrush(Colors.Gray);
                delete.Foreground = new SolidColorBrush(Colors.Gray);
            }
            _options.Items.Add(cut);
            _options.Items.Add(copy);
            _options.Items.Add(paste);
            _options.Items.Add(delete);
        }        

The CustomContextMenu class inherits from CustomPlaceHolder class and implements GetContent() of base class. In derived class AddToListBox() function will set the type of control which is going to display inside popup menu. Currently, I am using TextBlock control to display as ListBox content.

<CustomTextBox > Class

Public class CustomTextBox:TextBox
{
         CustomContextMenu contextMenu;

         private void CustomContextMenu()
        {
            this.MouseRightButtonDown +=
		new System.Windows.Input.MouseButtonEventHandler
			(CustomTextBox_MouseRightButtonDown);
            this.MouseRightButtonUp +=
		new System.Windows.Input.MouseButtonEventHandler
			(CustomTextBox_MouseRightButtonUp);
        }

         void CustomTextBox_MouseRightButtonUp
		(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (contextMenu == null)
            {
                contextMenu = new CustomContextMenu(this);
                contextMenu.Show(e.GetPosition(null));
            }
            else
            {
                contextMenu.Close();
                contextMenu.Show(e.GetPosition(null));
            }
        }

        void CustomTextBox_MouseRightButtonDown
		(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.Focus();
            e.Handled = true;
        }

        void Content_Resized(object sender, EventArgs e)
       {
            HtmlElement element = HtmlPage.Document.GetElementById("htmlBody");
            if (element != null)
            {
               element.AttachEvent("mousedown",
		new EventHandler<HtmlEventArgs>(RaiseHtmlEvent));
            }

            CloseCustomContextMenu();
        }
}

Here, CustomTextBox class derived from TextBox control provides context menu when user right clicks inside textbox. And to Setfocus (blink cursor when user clicks inside textbox) on customtextbox, we have to override OnGotFocus() function.

In this class, CustomContextMenu uses as member variable and gets initialized and gets active when right clicking inside textbox (MouseRightButtonDown/Up event).
To fire MouseRightButtonDown event make sure inside the event MouseRightButtonUp e.handled=true is set, else it won’t fire the event.

An important note: Just add this tag <body id="htmlBody"> to *.aspx page where Silverlight control is hosted. As in the above class, to track the “mousedown” event which will help to close the context menu when user clicks outside the Silverlight control (i.e on aspx/HTML page).

For those who are new to Silverlight and want to run out-of browser application, here are a few ways:

  1. Either right click on the application or click on “Install” button (If this is not installed on local machine will enable, else disable).

    Fourth.JPG

  2. Once clicked, it will pop-up a Security warning. Click on install.

    Fifth.JPG

  3. After this GoTo - Start-> All Programs: will display the below image:

    Sixth.JPG

Further Reading

History

  • 30th March, 2010: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here