testman tm
testman tm

Reputation: 89

How can i enable contextmenu menu only if the mouse position is on selected text in richTextBox?

The contextmenu will show in any case but the menu should be enable only if the mouse is on the selected text and not anywhere in the richTextBox area.

private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                for (int i = 0; i < contextMenu.MenuItems.Count; i++)
                {
                    if (richTextBox1.SelectedText != "")
                    {
                        contextMenu.MenuItems[i].Enabled = true;
                    }
                    else
                    {
                        contextMenu.MenuItems[i].Enabled = false;
                    }
                }
            }
        }

This enable the menuitems only when a text was selected. Now i want to add another condition that also if the mouse position is on the selected text then enable true.

If not enable false. So there should be two conditions one if text selected and second if the mouse is on any part of the selected text. Not sure yet how to make the second condition.

Update

What i tried now:

private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                int positionToSearch = richTextBox1.GetCharIndexFromPosition(e.Location);
                bool isInSelectedText = positionToSearch >= richTextBox1.SelectionStart && positionToSearch < richTextBox1.SelectionStart + richTextBox1.SelectionLength;
                for (int i = 0; i < contextMenu.MenuItems.Count; i++)
                {
                    if (richTextBox1.SelectedText != "" &&
                        isInSelectedText == true)
                    {
                        contextMenu.MenuItems[i].Enabled = true;
                    }
                    else
                    {
                        contextMenu.MenuItems[i].Enabled = false;
                    }
                }
            }
        }

But when i make right click on the selected text it will enable the menu but then if i make right click in other places in the richtextbox area the menu will be still enabled and i want it to be enabled only on the selected text.

And if no selected text at all enable false the menu.

I'm adding the context menu once in the form load event:

private void Form1_Load(object sender, EventArgs e)
        {
            contextMenu = new System.Windows.Forms.ContextMenu();
            MenuItem menuItem = new MenuItem("Cut");
            menuItem.Click += new EventHandler(CutAction);
            contextMenu.MenuItems.Add(menuItem);
            menuItem = new MenuItem("Copy");
            menuItem.Click += new EventHandler(CopyAction);
            contextMenu.MenuItems.Add(menuItem);
            menuItem = new MenuItem("Paste");
            menuItem.Click += new EventHandler(PasteAction);
            contextMenu.MenuItems.Add(menuItem);
            richTextBox1.ContextMenu = contextMenu;

            for (int i = 0; i < contextMenu.MenuItems.Count; i++)
            {
                contextMenu.MenuItems[i].Enabled = false;
            }
        }

Upvotes: 0

Views: 1310

Answers (2)

user6144226
user6144226

Reputation: 633

You can use the richTextBox.GetCharIndexFromPosition function to get the index(position in the richTextBox text) of the character closest to the checked point. Then simply verify if this index is between the start and end of the selection

int positionToSearch = richTextBox1.GetCharIndexFromPosition(e.Location);
bool isInSelectedText = positionToSearch >= richTextBox1.SelectionStart && positionToSearch < richTextBox1.SelectionStart + richTextBox1.SelectionLength

Since you are checking if the Left button is pressed during MouseMove as a way of detecting user selection in the following line if(e.Button == System.Windows.Forms.MouseButtons.Left)

Your code does not handle unselection as well as text selection made in different ways (Keyboard) This can be improved by hooking up to the SelectionChangedEvent to detect selection. The same could be said about starting the context menu from the keyboard.

To handle both cases you could:

Introduce two fields:

bool _isTextSelected = false;
bool _isInSelectedText = false;

Extract the code to enable the context menu to separate method

    private void EnableContextMenu()
    {
        for (int i = 0; i < contextMenu.MenuItems.Count; i++)
        {
            if (_isInSelectedText == true && _isTextSelected)
            {
                contextMenu.MenuItems[i].Enabled = true;
            }
            else
            {
                contextMenu.MenuItems[i].Enabled = false;
            }

        }
    }

Call this method when any of these two states changes

private void richTextBox1_SelectionChanged(object sender, EventArgs e)
{
    _isTextSelected = richTextBox1.SelectedText != "";
    EnableContextMenu();
}

private void richTextBox1_MouseMove(object sender, MouseEventArgs e)
{
    int positionToSearch = richTextBox1.GetCharIndexFromPosition(e.Location);
    _isInSelectedText = positionToSearch >= richTextBox1.SelectionStart && positionToSearch < richTextBox1.SelectionStart + richTextBox1.SelectionLength;
    EnableContextMenu();
}

Upvotes: 1

blaze_125
blaze_125

Reputation: 2317

Here's my take on it. In this sample I'm not opening a context menu, instead I am appending to the RichTextBox when the mouse is clicked in the proper position.

This snippet needs a bit of work to be production worthy, especially around defining the "fudgeFactored" area but, the premise is there. In the code below I'm only caring about the starting position of the text selection, though if I was to make this a production script, I'd look at where it starts, where it ends, and then I would add the fudgeFactor to it.

using System;
using System.Drawing;
using System.Windows.Forms;

namespace ContextMenuOnRichText_45042370
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        private void doit(Point mouseClickedAtPosition)
        {
            if (txtbx_1.SelectedText != null)
            {
                //find out where the selected text is
                Point selectionposition = txtbx_1.GetPositionFromCharIndex(txtbx_1.SelectionStart);

                /*
                 * the user is not likely to click in the right spot every time,
                 * so let's make a fudgeFactor
                 */
                int fudgeFactor = 15;


                if ((mouseClickedAtPosition.X <= selectionposition.X + fudgeFactor && mouseClickedAtPosition.X >= selectionposition.X - fudgeFactor) && (mouseClickedAtPosition.Y <= selectionposition.Y + fudgeFactor && mouseClickedAtPosition.Y >= selectionposition.Y - fudgeFactor))
                {
                    /*
                     * If the right click happened within the fudgeFactored area, then append to the box(open your menu)
                     */
                    txtbx_1.AppendText("positions are matching");
                }
                else
                {
                    /*
                     * User did not right-click in the proper area
                     * don't show your menu
                     */
                    txtbx_1.AppendText("not matching" + Environment.NewLine);
                }
            }
        }

        private void txtbx_1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                doit(e.Location);
            }
        }
    }
}

Upvotes: 1

Related Questions