Solved

drag and drop text to specific location in multi-line text box

Posted on 2007-03-29
4
749 Views
Last Modified: 2008-01-09
hi there,

i have a list box that contains several types of custom tags that i would like to be able to drag on drop into a multi-line text box and have the text insert at the location of the cursor. It would also be good if the cursor position could be updated as the user moved the mouse over the textbox.

does anyone know how this might be done?
0
Comment
Question by:RepriseMIS
  • 2
4 Comments
 
LVL 15

Expert Comment

by:stanscott2
ID: 18821395
This isn't done using C#.  Instead, you use JavaScript for this.  Here's a tutorial on how to do it:

http://luke.breuer.com/tutorial/javascript-drag-and-drop-tutorial.aspx

You can also Google "JavaScript drag and drop" -- there are a lot of helpful tutorials and how-to pages out there.
0
 

Author Comment

by:RepriseMIS
ID: 18822564
i probably should've mentioned that this is a .NET Forms application, not a web page.
0
 
LVL 8

Accepted Solution

by:
Rytmis earned 500 total points
ID: 18828367
I found this interesting, so I thought I'd give it a stab.

This is done on .NET 2.0, so if you're on 1.1, you'll have to combine the partial classes.

MainForm.Designer.cs:

namespace DragTestApp
{
      partial class MainForm
      {
            /// <summary>
            /// Designer variable used to keep track of non-visual components.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
            
            /// <summary>
            /// Disposes resources used by the form.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                  if (disposing) {
                        if (components != null) {
                              components.Dispose();
                        }
                  }
                  base.Dispose(disposing);
            }
            
            /// <summary>
            /// This method is required for Windows Forms designer support.
            /// Do not change the method contents inside the source code editor. The Forms designer might
            /// not be able to load this method if it was changed manually.
            /// </summary>
            private void InitializeComponent()
            {
                  this.textBox1 = new System.Windows.Forms.TextBox();
                  this.listBox1 = new System.Windows.Forms.ListBox();
                  this.SuspendLayout();
                  //
                  // textBox1
                  //
                  this.textBox1.AllowDrop = true;
                  this.textBox1.Location = new System.Drawing.Point(150, 18);
                  this.textBox1.Multiline = true;
                  this.textBox1.Name = "textBox1";
                  this.textBox1.Size = new System.Drawing.Size(277, 370);
                  this.textBox1.TabIndex = 1;
                  this.textBox1.DragOver += new System.Windows.Forms.DragEventHandler(this.TextBox1DragOver);
                  this.textBox1.DragDrop += new System.Windows.Forms.DragEventHandler(this.TextBox1DragDrop);
                  //
                  // listBox1
                  //
                  this.listBox1.FormattingEnabled = true;
                  this.listBox1.Items.AddRange(new object[] {
                                                      "Text",
                                                      "More text",
                                                      "Wheee!"});
                  this.listBox1.Location = new System.Drawing.Point(33, 18);
                  this.listBox1.Name = "listBox1";
                  this.listBox1.Size = new System.Drawing.Size(90, 121);
                  this.listBox1.TabIndex = 2;
                  this.listBox1.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(this.ListBox1QueryContinueDrag);
                  this.listBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ListBox1MouseMove);
                  this.listBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ListBox1MouseDown);
                  this.listBox1.GiveFeedback += new System.Windows.Forms.GiveFeedbackEventHandler(this.ListBox1GiveFeedback);
                  //
                  // MainForm
                  //
                  this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                  this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                  this.ClientSize = new System.Drawing.Size(601, 523);
                  this.Controls.Add(this.listBox1);
                  this.Controls.Add(this.textBox1);
                  this.Name = "MainForm";
                  this.Text = "S";
                  this.ResumeLayout(false);
                  this.PerformLayout();
            }
            private System.Windows.Forms.ListBox listBox1;
            private System.Windows.Forms.TextBox textBox1;
      }
}

MainForm.cs: this is where the interesting stuff happens. Drag'n'drop is fairly straightforward, but getting the position for the caret involves some P/Invoke magic.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace DragTestApp
{
      /// <summary>
      /// Description of MainForm.
      /// </summary>
      public partial class MainForm : Form
      {
            
            [DllImport("user32.dll")]
            private static extern Int32 SendMessage(IntPtr hwnd, Int32 wMsg, Int32 wParam, Int32 lParam);
            
            private const Int32 EM_CHARFROMPOS = 215;
            
            private static int GetCharFromPos(IntPtr hwnd, Point pos) {
                  DWORD param = new DWORD(pos.X, pos.Y);
            
                  return DWORD.MakeLong(SendMessage(hwnd, EM_CHARFROMPOS, 0, param.LongValue)).LoWord;
            }
            
            [StructLayout(LayoutKind.Explicit)]
            private struct DWORD {
                  [FieldOffset(0)] public int LongValue;
                  [FieldOffset(0)] public short LoWord;
                  [FieldOffset(2)] public short HiWord;
                  
                  public DWORD(int lowValue, int highValue) {
                        this.LongValue = 0;
                        this.LoWord = (short) lowValue;
                        this.HiWord = (short) highValue;
                  }
                  
                  public static DWORD MakeLong(int longValue) {
                        DWORD result = new DWORD();
                        result.LongValue = longValue;
                        return result;
                  }
            }            
            
            [STAThread]
            public static void Main(string[] args)
            {
                  Application.EnableVisualStyles();
                  Application.SetCompatibleTextRenderingDefault(false);
                  Application.Run(new MainForm());
            }
            private Rectangle dragThreshold = Rectangle.Empty;
            private int listDragIndex = ListBox.NoMatches;
            
            public MainForm()
            {
                  //
                  // The InitializeComponent() call is required for Windows Forms designer support.
                  //
                  InitializeComponent();
                  
                  //
                  // TODO: Add constructor code after the InitializeComponent() call.
                  //
            }
            
            void ListBox1GiveFeedback(object sender, GiveFeedbackEventArgs e)
            {
                  
            }
            
            void ListBox1MouseDown(object sender, MouseEventArgs e)
            {
                  int dragIndex = listBox1.IndexFromPoint(e.X, e.Y);
                  if (dragIndex != ListBox.NoMatches) {
                        dragThreshold = GetDragThreshold(e.X, e.Y);
                        listDragIndex = dragIndex;
                  }
                  else {
                        dragThreshold = Rectangle.Empty;
                  }
            }
            
            private static Rectangle GetDragThreshold(int x, int y) {
                  
                  return new Rectangle(new Point(x - (SystemInformation.DragSize.Width / 2),
                                                 y - (SystemInformation.DragSize.Height / 2)),
                                       SystemInformation.DragSize);
            }
            
            void ListBox1MouseMove(object sender, MouseEventArgs e)
            {
                  if (LeftMouseDown(e) && OverThreshold(e.X, e.Y)) {
                        Console.WriteLine("Dragging");
                        DragDropEffects drag =
                              listBox1.DoDragDrop(listBox1.Items[listDragIndex], DragDropEffects.All);
                        if (drag == DragDropEffects.Copy) {
                              
                        }
                  }
            }
            
            private static bool LeftMouseDown(MouseEventArgs e) {
                  return (e.Button & MouseButtons.Left) == MouseButtons.Left;
            }
            
            private bool OverThreshold(int x, int y) {
                  return dragThreshold != Rectangle.Empty
                        && !dragThreshold.Contains(x, y);
            }
            
            void TextBox1DragOver(object sender, DragEventArgs e)
            {
                  e.Effect = DragDropEffects.Copy;
                  textBox1.Focus();      
                  Point p = textBox1.PointToClient(new Point(e.X, e.Y));
                  textBox1.SelectionLength = 0;
                  textBox1.SelectionStart = GetCharFromPos(textBox1.Handle, p);

            }
            
            void TextBox1DragDrop(object sender, DragEventArgs e)
            {
                  textBox1.Paste((string) e.Data.GetData(typeof(System.String)));
            }

            void ListBox1QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
            {
                  if (!this.DesktopBounds.Contains(GetOffsetPosition(Control.MousePosition)))
                        e.Action = DragAction.Cancel;
            }
            
            private static Point GetOffsetPosition(Point p) {
                  Point screenOffset = SystemInformation.WorkingArea.Location;
                  return new Point(p.X - screenOffset.X, p.Y - screenOffset.Y);
            }            

      }
}

I hacked this together based on a couple of different tutorials and some MSDN searching. It's not perfect, but it should get you started.

HTH,

-Rytmis
0
 
LVL 8

Expert Comment

by:Rytmis
ID: 18828371
Also, please ignore the couple of bits of leftover code I neglected to remove. :)
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
Windows 10 is mostly good. However the one thing that annoys me is how many clicks you have to do to dial a VPN connection. You have to go to settings from the start menu, (2 clicks), Network and Internet (1 click), Click VPN (another click) then fi…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…

863 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

28 Experts available now in Live!

Get 1:1 Help Now