宇宙仮面の
C# Programming

 

Imageドラッグ アンド ドロップ

開発環境: Visual Studio 2003 

1.目次

2.目的

ドラッグアンドドロップについて質問があったので、TextBox, ListView, TreeView の Drag and Drop についてまとめます。

3.参考書

(1) MSDN(US) Dran and Drop
(2) C# Corner

4.ドラッグアンドドロップする方法

関連するプロパティ、イベント、メソッドは次のとおりです。
プロパティ説明
AllowDropコントロールドラッグアンドドロップを受け付けるかどうかを設定、取得します。
これを true にする必要がある。

イベント説明
DragEnterオブジェクトがコントロールの境界内にドラッグされると発生します。
DragOverオブジェクトがコントロールの境界を超えてドラッグされると発生します。
DragDropドラッグ アンド ドロップ操作が完了したときに発生します。
DragLeaveオブジェクトがコントロールの境界の外へドラッグされると発生します。
メソッド説明
DoDragDropドラッグ アンド ドロップ操作を開始します。
以下では、順に TextBox, ListView, TreeView のドラッグアンドドロップを作ります。

注意
扱えるデータは、基本マネージ クラス (String 、 Bitmap 、Metafile)、
あるいは ISerializable または IDataObject を実装するオブジェクトのいずれかである必要があります。
TextBox では、string, ListView, TreeView は、ListViewItem, TreeNodeが ISerializable を実装するため、
扱うことができます。

参考: DataGrid各行のドラッグアンドドロップはできるのか?
そのままではできません。次のURLが参考になるかもしれません。
「行をD&Dする」のではなく、「D&Dでカラムを入れ替える」方法が記述されています。

http://www.c-sharpcorner.com/Code/2002/Aug/DataGridCustomizationP4.asp

5. TextBox 間のドラッグアンドドロップ

まずは、あまり使い道は無いと思いますが、簡単な例で、TextBox 間で、テキストをドラッグアンドドロップする場合についてです。

TextBox の AllowDrop プロパティを true にしておく必要があります。

AllowDrop プロパティの設定
this.textBox1.AllowDrop = true;

次に、ドラッグアンドドロップの開始を何らかの方法で判断する必要があります。
ここでは、あまりいい方法ではないですが、マウスで TextBox を押したときに ドラッグアンドドロップが開始されたと判断します。
このときの引数で、引き渡すデータと、ドラッグ アンド ドロップ操作の効果を指定します。
ここでは単にコピーだけを許すために、DragDropEffects.Copy を指定します。
DragDropEffects のメンバーは次のとおりです。
DragDropEffects
All
データがコピーされ、ドラッグ ソースから削除され、ドロップ ターゲットでスクロールされます。
Copyデータはドロップ ターゲットにコピーされます。
Linkドラッグ ソースのデータはドロップ ターゲットにリンクされます。
Moveドラッグ ソースのデータはドロップ ターゲットに移動されます。
Noneドロップ ターゲットはデータを受け付けません。
Scrollドロップ ターゲットでスクロールが開始されようとしているか、または現在スクロールが行われています。

次に、ドラッグアンドドロップする対象の TextBox 側でイベントが発生しますので、その処理を記述します。
ここで、DragEnter, DragOver の場合に、e.Effect にコピーなら、DragDropEffects.Copy を指定します。
これは、DoDragDrop で指定しておく必要があります。
この DragDropEffects の設定により コピーの + マーク、移動時は+マークなし、リンク時はリンクマークが表示されるようになります。

DragEnter(...)
        private void textBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {
            if(e.Data.GetDataPresent(DataFormats.Text))
                e.Effect = DragDropEffects.Copy;                 
        }
DragOver(...)
        private void textBox1_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
        {      
            if(e.Data.GetDataPresent(DataFormats.Text))
                e.Effect = DragDropEffects.Copy;                 
        }
DragDrop(...)
        private void textBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
        {
            if(e.Data.GetDataPresent(DataFormats.Text))
            {
                this.textBox1.Text = (string)e.Data.GetData(DataFormats.Text);
            }       
        }

5.1 テキストボックスのドラッグアンドドロップのソースコード

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;

namespace DragAndDropTextBox
{
        /// <summary>
        /// Form1 の概要の説明です。
        /// </summary>
        public class Form1 : System.Windows.Forms.Form
        {
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.TextBox textBox2;
                /// <summary>
                /// 必要なデザイナ変数です。
                /// </summary>
                private System.ComponentModel.Container components = null;

                public Form1()
                {
                        //
                        // Windows フォーム デザイナ サポートに必要です。
                        //
                        InitializeComponent();

                        //
                        // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
                        //
                }

                /// <summary>
                /// 使用されているリソースに後処理を実行します。
                /// </summary>
                protected override void Dispose( bool disposing )
                {
                        if( disposing )
                        {
                                if (components != null) 
                                {
                                        components.Dispose();
                                }
                        }
                        base.Dispose( disposing );
                }

                #region Windows フォーム デザイナで生成されたコード 
                /// <summary>
                /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
                /// コード エディタで変更しないでください。
                /// </summary>
                private void InitializeComponent()
                {
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.textBox2 = new System.Windows.Forms.TextBox();
            this.SuspendLayout();
            // 
            // textBox1
            // 
            this.textBox1.AllowDrop = true;
            this.textBox1.Location = new System.Drawing.Point(40, 40);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(184, 19);
            this.textBox1.TabIndex = 0;
            this.textBox1.Text = "textBox1";
            this.textBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.textBox1_MouseDown);
            this.textBox1.DragOver += new System.Windows.Forms.DragEventHandler(this.textBox1_DragOver);
            this.textBox1.DragDrop += new System.Windows.Forms.DragEventHandler(this.textBox1_DragDrop);
            this.textBox1.DragEnter += new System.Windows.Forms.DragEventHandler(this.textBox1_DragEnter);
            // 
            // textBox2
            // 
            this.textBox2.AllowDrop = true;
            this.textBox2.Location = new System.Drawing.Point(40, 112);
            this.textBox2.Name = "textBox2";
            this.textBox2.Size = new System.Drawing.Size(184, 19);
            this.textBox2.TabIndex = 1;
            this.textBox2.Text = "textBox2";
            this.textBox2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.textBox2_MouseDown);
            this.textBox2.DragOver += new System.Windows.Forms.DragEventHandler(this.textBox2_DragOver);
            this.textBox2.DragDrop += new System.Windows.Forms.DragEventHandler(this.textBox2_DragDrop);
            this.textBox2.DragEnter += new System.Windows.Forms.DragEventHandler(this.textBox2_DragEnter);
            // 
            // Form1
            // 
            this.AllowDrop = true;
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.textBox2);
            this.Controls.Add(this.textBox1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
                #endregion

                /// <summary>
                /// アプリケーションのメイン エントリ ポイントです。
                /// </summary>
                [STAThread]
                static void Main() 
                {
                        Application.Run(new Form1());
                }

        // -------- textBox1 ---------
        private void textBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            this.textBox1.SelectAll();
            this.DoDragDrop(this.textBox1.Text, DragDropEffects.Copy);
        }

        private void textBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {
            Debug.WriteLine("DragEnter");
            if(e.Data.GetDataPresent(DataFormats.Text))
                e.Effect = DragDropEffects.Copy;                 
        }

        private void textBox1_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
        {      
            Debug.WriteLine("DragEnter");
            if(e.Data.GetDataPresent(DataFormats.Text))
                e.Effect = DragDropEffects.Copy;                 
        }

        private void textBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
        {
            Debug.WriteLine("DragDrop");
            if(e.Data.GetDataPresent(DataFormats.Text))
            {
                this.textBox1.Text = (string)e.Data.GetData(DataFormats.Text);
            }       
        }

        // -------- textBox2 ---------
        private void textBox2_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            this.textBox2.SelectAll();
            this.DoDragDrop(this.textBox2.Text, DragDropEffects.Copy);
        }

        private void textBox2_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
        {
            Debug.WriteLine("DragDrop");
            if(e.Data.GetDataPresent(DataFormats.Text))
            {
                this.textBox2.Text = (string)e.Data.GetData(DataFormats.Text);
            }       
        }

        private void textBox2_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {        
            Debug.WriteLine("DragEnter");
            if(e.Data.GetDataPresent(DataFormats.Text))
                e.Effect = DragDropEffects.Copy;                 
        }

        private void textBox2_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
        {
            Debug.WriteLine("DragEnter");
            if(e.Data.GetDataPresent(DataFormats.Text))
                e.Effect = DragDropEffects.Copy;                 
        }
        }
}

6.ListView のドラッグアンドドロップ

ListView のドラッグアンドドロップでは、複数のアイテムがあり、そのアイテムをドラッグアンドドロップできるようにします。
ListView には、このアイテムを選択してドラッグしたことを判別するために、 ItemDrag イベントがあります。
この ItemDrag イベントで、DoDragDrop メソッドを呼び出して、ドラッグアンドドロップの開始を指定してやればいいことになります。
まず、ListView の AllowDrop プロパティを true にしておく必要があります。
それから、ListView は複数のアイテムを選択できるので、簡単にするため、MultiSelect を false にします。
さらに、ListView は、複数のサブアイテムを持つことができますが、これも簡単のために、サブアイテムを持たないようにします。
そこで、View のスタイルを List にします。

ListView プロパティの設定
this.listView1.AllowDrop = true;
this.listView1.MultiSelect = false;
this.listView1.View = System.Windows.Forms.View.List;

次に、アイテムを選択してドラッグしたときに発生する ItemDrag イベントで、DoDragDrop メソッドを呼び出して、ドラッグアンドドロップを開始します。
ここでは、コピーと、移動を実装します。そこで、どのドラッグ操作が発生できるかを示す allowedEffect パラメータに、DragDropEffects.Copy| DragDropEffects.Moveを指定します。
ItemDrag(...)
private void listView1_ItemDrag(object sender, System.Windows.Forms.ItemDragEventArgs e)
{
        listView1.DoDragDrop((ListViewItem)e.Item, DragDropEffects.Copy| DragDropEffects.Move);         
}

次に、ドラッグした時に発生する DragEnter イベント処理を記述します。
まず、DragEventArgs.Data でドラッグできるアイテムが存在するかチェックします。
次に、シフトキーを押しながらドラッグした場合にはMove、そのままもしくはコントロールキーを押しながらドラッグした場合はCopy とします。

DragEnter(...)
private void listView1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{               
    if(e.Data.GetDataPresent(typeof(ListViewItem)))
       {
       if ( (e.KeyState & 0x4) > 0)    // Shift Key (MOVE)
                   e.Effect = DragDropEffects.Move;                                
            else if ( e.KeyState == 0x1 || (e.KeyState & 0x8) > 0)  
             // Mouse Left or Control Key (COPY)
                e.Effect = DragDropEffects.Copy;                        
       } 
}
次に、ドラッグしたアイテムが上に移動した場合に発生する DragOver イベント処理を記述します。
まず、DragEventArgs.Data でドラッグできるアイテムが存在するかチェックします。
次に、GetItemAt() メソッドでどのアイテムの上に移動したのかを判断する必要があります。
そして、そのアイテムをセレクト状態にしてあげます。これは必要ではないんですが、Explorer の動きに合わせてみました。
DragOver(...)
private void listView1_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
{
      if(e.Data.GetDataPresent(typeof(ListViewItem)))
      {
            Point p = this.listView1.PointToClient(new Point(e.X, e.Y));
            ListViewItem item = this.listView1.GetItemAt(p.X, p.Y);
            if(item != null)
                item.Selected = true;
      }
}
最後に、ドロップした時に発生する DragDrop イベント処理を記述します。
まず、DragEventArgs.Data でドラッグできるアイテムが存在するかチェックします。
このとき、アイテムが存在しない場所を選択すると、IndexOf() が -1 を返すので、その場合はリストの最後に追加するようにします。
また、移動先が自分自身より下の場合(選択した場所より1つ下に挿入する)と、
自分自身より上の場合(選択した場所に挿入する)で、挿入ポイントが違ってきますので、destIndex でその調整をしています。
あとは、その場所に Insert() してあげればOKです。

ただ、Move の場合には、ソースのアイテムを削除してあげる必要があります。
このために、e.KeyState でシフトキーが押されているかどうかを判断して、Move の場合にはソースのアイテムを削除します。
DragDrop(...)
private void listView1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
      // ドラッグできるアイテムが存在するかチェックします。
      if(e.Data.GetDataPresent(typeof(ListViewItem)))
      {
          ListViewItem srcItem = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
          // 
          Point p = this.listView1.PointToClient(new Point(e.X, e.Y));
          ListViewItem item = this.listView1.GetItemAt(p.X, p.Y);
          int destIndex = this.listView1.Items.IndexOf(item);

          // アイテムが存在しない場所を選択すると、IndexOf() が -1 を返すので、
          // その場合はリストの最後に追加するようにします。
          if (destIndex == -1)
              destIndex = this.listView1.Items.Count;
          else if (destIndex > srcItem.Index) 
              // 移動先が自分自身より下の場合、選択した場所より1つ下に挿入する。
              // 自分自身より上の場合、選択した場所に挿入する。
              destIndex++;
          // その場所に挿入する。
          ListViewItem newItem = this.listView1.Items.Insert(destIndex, srcItem.Text);
          newItem.Selected = true;
          // Move の場合には、ソースのアイテムを削除してあげる必要があります。
          // Shift Key (MOVE)
          if ( (e.KeyState & 0x4) > 0)    
          {
              this.listView1.Items.Remove(srcItem);
          }
     }
}

6.1 リストビューのドラッグアンドドロップのソースコード

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.Win32;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace SavePosition2
{
        /// <summary>
        /// Form1 の概要の説明です。
        /// </summary>
        [Serializable()]
        public class Form1 : System.Windows.Forms.Form, ISerializable
        {
                /// <summary>
                /// 必要なデザイナ変数です。
                /// </summary>
                private System.ComponentModel.Container components = null;
                private const string registryKey = @"Software\Uchukamen\MyApplication\2.0\Form1";

                public Form1()
                {
                        //
                        // Windows フォーム デザイナ サポートに必要です。
                        //
                        InitializeComponent();

                        //
                        // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
                        //
                }

                /// <summary>
                /// 使用されているリソースに後処理を実行します。
                /// </summary>
                protected override void Dispose( bool disposing )
                {
                        if( disposing )
                        {
                                if (components != null) 
                                {
                                        components.Dispose();
                                }
                        }
                        base.Dispose( disposing );
                }

                #region Windows Form Designer generated code
                /// <summary>
                /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
                /// コード エディタで変更しないでください。
                /// </summary>
                private void InitializeComponent()
                {
                        // 
                        // Form1
                        // 
                        this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
                        this.ClientSize = new System.Drawing.Size(292, 266);
                        this.Name = "Form1";
                        this.Text = "Form1";
                        this.Closing += new System.ComponentModel.CancelEventHandler(this.OnClosing);
                        this.Load += new System.EventHandler(this.Form1_Load);

                }
                #endregion

                /// <summary>
                /// アプリケーションのメイン エントリ ポイントです。
                /// </summary>
                [STAThread]
                static void Main() 
                {
                        Application.Run(new Form1());
                }

                /// シグネチャ コンストラクタで、デシリアライズ時に Formatterにより呼び出される。
                public Form1(SerializationInfo info, StreamingContext ctxt)
                {
                        this.Location = new Point ((int)info.GetValue("Location.X", typeof(int)), 
                                                                           (int)info.GetValue("Location.Y", typeof(int)));
                        this.Size = (Size)info.GetValue("Size", typeof(Size));
                }
                
                /// シリアライズ時に呼ばれる。
                /// ISerializable インターフェイスの実装
                public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
                {
                        info.AddValue("Location.X", this.Location.X);
                        info.AddValue("Location.Y", this.Location.Y);
                        info.AddValue("Size", this.Size);
                }

                private void Form1_Load(object sender, System.EventArgs e)
                {
                        try
                        {
                                // カレントユーザのレジストリをオープンする。
                                RegistryKey key = Registry.CurrentUser.OpenSubKey(registryKey);

                                // 一番最初は、レジストリに登録されてない。
                                // その場合は、何もしない。
                                if (key == null)
                                {
                                        return;
                                }

                                // レジストリからシリアライズされたデータを読み込む。
                                byte [] buff = (byte[])(key.GetValue("Form1"));
                                // メモリをストリームに変える。
                                MemoryStream memoryStream = new System.IO.MemoryStream(buff);
                                // BinaryFormatter を作る。
                                BinaryFormatter binaryFormatter = new BinaryFormatter();
                                // メモリストリームをバイナリーフォーマッタでデシリアライズする。
                                Form1 form1Obj = (Form1)(binaryFormatter.Deserialize(memoryStream));
                                // 直接Form インスタンスを置き換えできないので、各要素を代入する。
                                this.Size = form1Obj.Size; 
                                this.Location = form1Obj.Location; 
                                // ストリーム、レジストリを閉じる。
                                memoryStream.Close();
                                key.Close();
                        }
                        catch(Exception exc)
                        {
                                MessageBox.Show(exc.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                }

                private void OnClosing(object sender, System.ComponentModel.CancelEventArgs e)
                {
                        try
                        {
                                // カレントユーザにレジストリをクリエイトする。
                                RegistryKey key = Registry.CurrentUser.CreateSubKey(registryKey);
                                if (key == null)
                                {
                                        MessageBox.Show("レジストリの生成に失敗しました", this.Text, MessageBoxButtons.OK);
                                        return;
                                }
                                // メモリストリームを作る。
                                MemoryStream memoryStream = new MemoryStream();
                                // バイナリーフォーマッターを作る。
                                BinaryFormatter BinaryFormatter = new BinaryFormatter();
                                // バイナリーフォーマッターで、Form1 そのものをシリアライズする。
                                BinaryFormatter.Serialize(memoryStream, this);
                                // シリアライズしたメモリストリームをレジストリに書き出す。
                                key.SetValue("Form1", memoryStream.GetBuffer());
                                // ストリーム、レジストリを閉じる。
                                memoryStream.Close(); 
                                key.Close();
                        }
                        catch(Exception exc)
                        {
                                MessageBox.Show(exc.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                }
        }
}

7.TreeView のドラッグアンドドロップ

TreeView の場合には、TreeNode に対する操作になるので、ListView とはちょっと異なってきます。
まず、TreeView の AllowDrop プロパティを true にしておく必要があります。

TreeView プロパティの設定
this.treeView1.AllowDrop = true;

次に、ドラッグした時に発生する DragEnter イベント処理を記述します。
まず、DragEventArgs.Data でドラッグできるアイテムが存在するかチェックします。
次に、シフトキーを押しながらドラッグした場合にはMove、そのままもしくはコントロールキーを押しながらドラッグした場合はCopy とします。

DragEnter(...)
private void treeView1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
    if(e.Data.GetDataPresent(typeof(TreeNode)))
    {
         if ( (e.KeyState & 0x4) > 0)    // Shift Key (MOVE)
             e.Effect = DragDropEffects.Move;                            
         else if ( e.KeyState == 0x1 || (e.KeyState & 0x8) > 0)  
             // Mouse Left or Control Key (COPY)
            e.Effect = DragDropEffects.Copy;                    
    } 
}
次に、ドラッグしたアイテムが上に移動した場合に発生する DragOver イベント処理を記述します。
ListView の時と違って、TreeView でサブノードがある場合には、サブノードを広げてあげる(Expand)必要があります。
DragOver(...)
private void treeView1_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
{
    if(e.Data.GetDataPresent(typeof(TreeNode)))
    {
        Point p = this.treeView1.PointToClient(new Point(e.X, e.Y));
        TreeNode item = this.treeView1.GetNodeAt(p.X, p.Y);
        // ノードを展開する。
        item.Expand();
    }
}
最後に、ドロップした時に発生する DragDrop イベント処理を記述します。
まず、DragEventArgs.Data でドラッグできるアイテムが存在するかチェックします。
次に、ドロップ先のノード(targetNode) を特定します。
そのターゲットノードに、ソースノードのクローンを追加します。。

ただ、Move の場合には、ソースのアイテムを削除してあげる必要があります。
このために、e.KeyState でシフトキーが押されているかどうかを判断して、Move の場合にはソースのアイテムを削除します。
DragDrop(...)
private void treeView1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
    if(e.Data.GetDataPresent(typeof(TreeNode)))
    {
        TreeNode srcNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
        // ドロップ先のノード(targetNode)を特定する。
        Point p = this.treeView1.PointToClient(new Point(e.X, e.Y));
        TreeNode targetNode = this.treeView1.GetNodeAt(p.X, p.Y);
        // ソースノードのクローンをターゲットノードに追加する。
        targetNode.Nodes.Add((TreeNode)srcNode.Clone());
        if ( (e.KeyState & 0x4) > 0)    
        {
            this.treeView1.Nodes.Remove(srcNode);
        }
    }        
}


7.1 ツリービューのドラッグアンドドロップのソースコード

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;

namespace DragAndDropTreeView
{
    /// <summary>
    /// Form1 の概要の説明です。
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.TreeView treeView1;
        /// <summary>
        /// 必要なデザイナ変数です。
        /// </summary>
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            //
            // Windows フォーム デザイナ サポートに必要です。
            //
            InitializeComponent();

            //
            // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
            //
        }

        /// <summary>
        /// 使用されているリソースに後処理を実行します。
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows フォーム デザイナで生成されたコード 
        /// <summary>
        /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディタで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.treeView1 = new System.Windows.Forms.TreeView();
            this.SuspendLayout();
            // 
            // treeView1
            // 
            this.treeView1.AllowDrop = true;
            this.treeView1.ImageIndex = -1;
            this.treeView1.Location = new System.Drawing.Point(8, 8);
            this.treeView1.Name = "treeView1";
            this.treeView1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
            	new System.Windows.Forms.TreeNode("ノード0"),
            	new System.Windows.Forms.TreeNode("ノード1", new System.Windows.Forms.TreeNode[] {
            	new System.Windows.Forms.TreeNode("ノード2", new System.Windows.Forms.TreeNode[] {
            	new System.Windows.Forms.TreeNode("ノード3")})}),
            	new System.Windows.Forms.TreeNode("ノード4", new System.Windows.Forms.TreeNode[] {
            	new System.Windows.Forms.TreeNode("ノード5", new System.Windows.Forms.TreeNode[] {
            	new System.Windows.Forms.TreeNode("ノード6")})}),
            	new System.Windows.Forms.TreeNode("ノード7", new System.Windows.Forms.TreeNode[] {
            	new System.Windows.Forms.TreeNode("ノード8", new System.Windows.Forms.TreeNode[] {
            	new System.Windows.Forms.TreeNode("ノード9", new System.Windows.Forms.TreeNode[] {
new System.Windows.Forms.TreeNode("ノード10")})})})});
            this.treeView1.SelectedImageIndex = -1;
            this.treeView1.Size = new System.Drawing.Size(256, 232);
            this.treeView1.TabIndex = 0;
            this.treeView1.DragOver += new System.Windows.Forms.DragEventHandler(this.treeView1_DragOver);
            this.treeView1.DragEnter += new System.Windows.Forms.DragEventHandler(this.treeView1_DragEnter);
            this.treeView1.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.treeView1_ItemDrag);
            this.treeView1.DragDrop += new System.Windows.Forms.DragEventHandler(this.treeView1_DragDrop);
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.treeView1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
        #endregion

        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new Form1());
        }
        
        private void treeView1_ItemDrag(object sender, System.Windows.Forms.ItemDragEventArgs e)
        {
            Debug.WriteLine("ItemDrag");
            treeView1.DoDragDrop((TreeNode)e.Item, DragDropEffects.Copy| DragDropEffects.Move); 
        }

        private void treeView1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {
            Debug.WriteLine("DragEnter");
            if(e.Data.GetDataPresent(typeof(TreeNode)))
            {
                if ( (e.KeyState & 0x4) > 0)    // Shift Key (MOVE)
                    e.Effect = DragDropEffects.Move;                            
                else if ( e.KeyState == 0x1 || (e.KeyState & 0x8) > 0)  
                    // Mouse Left or Control Key (COPY)
                    e.Effect = DragDropEffects.Copy;                    
            } 
        }

        private void treeView1_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
        {
            if(e.Data.GetDataPresent(typeof(TreeNode)))
            {
                Point p = this.treeView1.PointToClient(new Point(e.X, e.Y));
                TreeNode item = this.treeView1.GetNodeAt(p.X, p.Y);
                // ノードを展開する。
                item.Expand();
                Debug.WriteLine("DragOver:" + item.FullPath);
            }
        }

        private void treeView1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
        {
            if(e.Data.GetDataPresent(typeof(TreeNode)))
            {
                TreeNode srcNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
                // ドロップ先のノード(targetNode)を特定する。
                Point p = this.treeView1.PointToClient(new Point(e.X, e.Y));
                TreeNode targetNode = this.treeView1.GetNodeAt(p.X, p.Y);
                // ソースノードのクローンをターゲットノードに追加する。
                targetNode.Nodes.Add((TreeNode)srcNode.Clone());
                if ( (e.KeyState & 0x4) > 0)    
                {
                    this.treeView1.Nodes.Remove(srcNode);
                }
            }        
        }
    }
}

8.変更履歴

2003/6/24 新規作成