Visual C# 2005如何執(zhí)行拖放操作

2010-08-28 10:50:09來源:西部e網(wǎng)作者:

就操作習(xí)慣而言,我們可以將Windows應(yīng)用程序的用戶分為兩大類,第一類是偏好使用鍵盤的用戶,第二類是偏好使用鼠標(biāo)的用戶。眾多的實(shí)踐經(jīng)驗(yàn)讓程序設(shè)計(jì)師充分了解到,務(wù)必提供熱鍵(會顯示出下劃線的快速字符鍵)與快捷鍵(例如:Ctrl+某字符的組合按鍵)給大量運(yùn)用鍵盤的用戶,但是卻反而常常忽略鼠標(biāo)用戶的需求。由于程序設(shè)計(jì)師本身就比較傾向于鍵盤用戶,因此特別強(qiáng)調(diào)鍵盤導(dǎo)向的功能是可以理解的,但是每一位程序設(shè)計(jì)師也應(yīng)該好好顧及鼠標(biāo)的完整支持才是。

其實(shí)鼠標(biāo)用戶所最期盼的就是對拖放操作的充分支持。仔細(xì)端詳大多數(shù)的Windows應(yīng)用軟件或Windows操作系統(tǒng)本身,我們會發(fā)現(xiàn)拖放能力是無處不在的。舉例來說,用戶早已非常習(xí)慣在Windows資源管理器中拖曳和置放文件,并且在Microsoft Word中拖曳和置放文字。

令人遺憾的是,只有極少數(shù)的VisualC#程序設(shè)計(jì)師會在他們所開發(fā)的應(yīng)用程序中提供完善的拖放功能,當(dāng)然,造成此現(xiàn)象的原因之一,就是要實(shí)現(xiàn)拖放功能確實(shí)有其困難度與復(fù)雜度。本節(jié)將讓您知道要利用Visual C#2003~2005以后的版本來實(shí)拖現(xiàn)放功能是多么簡單的一件事情。我們將實(shí)際展現(xiàn)如何在窗體內(nèi)、在窗體之間,以及在應(yīng)用程序之間移動和復(fù)制文字、圖片以及文件。

拖放操作是如何運(yùn)作的

拖放操作其實(shí)與剪切與粘貼(或復(fù)制與粘貼)沒有什么不同,只不過它是使用鼠標(biāo)而不是使用鍵盤。在這兩類操作中,您都會擁有一個來源(也就是您剪切或復(fù)制的對象)以及一個目標(biāo)(也就是您所粘貼之處)。不論是哪一種操作,在操作期間,都會在內(nèi)存中存在數(shù)據(jù)的一份副本。剪切與粘貼會使用到剪貼板,而拖放則會使用到一個DataObject對象,其實(shí)DataObject對象就好比是一個私有剪貼板。

在一個典型的拖放操作中,將會依序引發(fā)下列事件:

1.您可以通過調(diào)用源控件的DoDragDrop方法來初始化拖曳操作。DoDragDrop方法的語法如下所示:

DragDropEffects DoDragDrop(

Object data,


DragDropEffects allowedEffects)DoDragDrop方法會接受下列兩個參數(shù):
  • data參數(shù)用來指定所要拖曳(傳遞)的數(shù)據(jù)。
  • allowedEffects參數(shù)用來指定哪些操作(“復(fù)制”和/或“移動”)是被允許的。
    一個新的DataObject對象會自動被創(chuàng)建。

    2.接下來會引發(fā)源控件的GiveFeedback事件。在大多數(shù)的情況下,您并不需要去處理GiveFeedback事件,但是如果您想在拖曳期間顯示一個自定義的鼠標(biāo)指針,則可以在GiveFeedback事件處理函數(shù)中編寫程序代碼來完成此項(xiàng)設(shè)定。

    3.AllowDrop屬性被設(shè)定成True的任何控件都可以是置放目標(biāo)。您可以在設(shè)計(jì)階段在“屬性”窗口中將要作為目標(biāo)控件的AllowDrop屬性設(shè)定成True,或者是于運(yùn)行階段在窗體的Load事件處理函數(shù)中將要作為目標(biāo)控件的AllowDrop屬性設(shè)定成True。

    4.當(dāng)您將鼠標(biāo)指針移至任何一個控件的上方時,便會引發(fā)該控件的DragEnter事件。我們通常會在目標(biāo)控件的DragEnter事件處理函數(shù)中,使用GetDataPresent方法去檢測所拖曳的數(shù)據(jù)格式是否適用于目標(biāo)控件,并使用DragEventArgs類型參數(shù)的Effect屬性來設(shè)定所允許的置放操作。

    5.如果用戶在一個有效的置放目標(biāo)上放開鼠標(biāo)按鍵,將會引發(fā)目標(biāo)控件的DragDrop事件。我們通常會在目標(biāo)控件的DragDrop事件處理函數(shù)中編寫程序代碼,從DataObject對象擷取數(shù)據(jù)并將其顯示于目標(biāo)控件中。

    關(guān)于拖放操作,您還必須注意下列事項(xiàng):
    • 某些控件具有自定義的特定拖曳事件。例如,ListView與TreeView控件就擁有ItemDrag事件。
    • 當(dāng)一項(xiàng)拖曳操作正在執(zhí)行的時候,您可以處理QueryContinueDrag事件,該事件會向系統(tǒng)“要求使用權(quán)限”來繼續(xù)執(zhí)行拖曳操作。當(dāng)以該方法處理的時候,也是一種對調(diào)用那些對拖曳操作有影響的方法非常恰當(dāng)?shù)臅r機(jī)。比方說,當(dāng)鼠標(biāo)指針停留在TreeView控件上方的時候展開一個TreeNode。
    • 您也可以定義您自己的DataFormats。做法非常簡單,您只需將您的對象指定為SetData方法中的Object參數(shù),同時請確定所指定的對象是可序列化的。
    • 除此之外,您還可以使用KeyState屬性,以便根據(jù)拖放操作期間所按下的按鍵來產(chǎn)生特定效果。舉例來說,當(dāng)Ctrl鍵被按下時所拖曳的數(shù)據(jù)通常要進(jìn)行復(fù)制。
      拖曳文字 拖曳操作最簡單的實(shí)現(xiàn)就是將某一個TextBox控件中的文字移動或復(fù)制到另一個TextBox控件中。當(dāng)然,您也可以使用復(fù)制或剪切以及粘貼操作在兩個TextBox控件間復(fù)制或移動數(shù)據(jù),然而使用拖放操作來完成此類操作絕對會更有效率。

      程序范例CH8_DemoForm011.cs示范如何在兩個TextBox控件間拖曳文字,其功能特性如下所示:圖8.10示范如何拖曳文字
      • 如圖8.10所示,由于右側(cè)上方TextBox控件的AllowDrop屬性被設(shè)定成False,因此您無法從左側(cè)的TextBox控件中將文字拖放其中。
      • 如圖8.11所示,由于右側(cè)下方之TextBox控件的AllowDrop屬性被設(shè)定成True,因此您可以使用拖放方式將左側(cè)TextBox控件中的文字移動至右側(cè)下方的TextBox控件中。
      • 值得一提的是,如果您持續(xù)按Ctrl鍵,則可以使用拖放方式將左側(cè)TextBox控件的文字復(fù)制到右側(cè)下方的TextBox控件中(如圖8.12所示)。

        \

        圖8.11通過拖放操作來移動文字

        \

        圖8.12通過拖放操作來復(fù)制文字

        程序范例CH8_DemoForm011.cs在拖放操作方面的程序代碼如下所示:

        \// 聲明一個常量以便調(diào)試在拖曳期間Ctrl鍵是否被按下。
        \

        \
        constbyte CtrlMask =8;
        \
        \
        \
        \
        // 替左側(cè)的 TextBox 控件處理 MouseDown 事件。
        \
        \
        // 當(dāng)用戶在此控件的范圍內(nèi)按下鼠標(biāo)按鍵時便會引發(fā)此事件。
        \

        \
        privatevoid txtLeft_MouseDown(object sender, MouseEventArgs e)
        \
        ...{

        // 如果用戶按下鼠標(biāo)左鍵。

        if (e.Button == System.Windows.Forms.MouseButtons.Left)

        ...{

        // 選取文本框中所有的文字。

        txtLeft.SelectAll();



        // 初始化拖放操作。

        txtLeft.DoDragDrop(

        txtLeft.SelectedText,

        DragDropEffects.Move
        | DragDropEffects.Copy);

        }


        }

        \
        \
        \
        \
        // 處理右側(cè)下方 TextBox 控件的 DragEnter 事件。
        \
        \
        // 當(dāng)一個對象被拖曳至目標(biāo)控件的范圍內(nèi)時,就會引發(fā)
        \
        \
        // 目標(biāo)控件的 DragEnter 事件。
        \

        \
        privatevoid txtLowerRight_DragEnter(object sender, DragEventArgs e)
        \
        ...{

        // 檢查被拖曳的數(shù)據(jù)的類型是否適用于目標(biāo)控件。如果不適用,則拒絕置放。

        if (e.Data.GetDataPresent(DataFormats.Text))

        ...{

        // 如果在拖曳期間按著 Ctrl 鍵,則執(zhí)行復(fù)制操作;反之,則執(zhí)行移動操作。

        if ((e.KeyState & CtrlMask) == CtrlMask)

        ...{

        e.Effect
        = DragDropEffects.Copy;

        }


        else

        ...{

        e.Effect
        = DragDropEffects.Move;

        }


        }


        else

        ...{

        e.Effect
        = DragDropEffects.None;

        }


        }

        \
        \
        \
        \
        // 處理右側(cè)下方 TextBox 控件的 DragDrop 事件。
        \
        \
        // 當(dāng)用戶放開鼠標(biāo)按鍵時就會引發(fā)此事件,并終止拖放操作。
        \

        \
        privatevoid txtLowerRight_DragDrop(object sender, DragEventArgs e)
        \
        ...{

        txtLowerRight.Text
        = e.Data.GetData(

        DataFormats.Text).ToString();



        // 如果 Ctrl 鍵沒有被按下,移除源文字以便營造出移動文字的效果。

        if ((e.KeyState & CtrlMask) != CtrlMask)

        ...{

        txtLeft.Text
        ="";

        }


        }



        從以上的程序代碼可以看出,我們會在拖放源(也就是左側(cè)的TextBox控件)的MouseDown事件處理函數(shù)中判斷鼠標(biāo)按鍵已經(jīng)被按下,而且如果用戶是按下鼠標(biāo)左鍵的話,便會調(diào)用DoDragDrop 方法并傳遞下列兩個參數(shù)給它以便初始化拖曳操作:
        • 我們使用TextBox控件中被選取的文字作為第一個參數(shù)(即data參數(shù))的值,也就是TextBox控件中的文字將成為被拖曳的數(shù)據(jù)。
        • 我們將第二個參數(shù)(也就是allowedEffects參數(shù))設(shè)定成DragDropEffects.Move Or DragDropEffects.Copy,以便允許用戶移動或復(fù)制。
          我們會于置放目標(biāo)(也就是右側(cè)下方的TextBox控件)的DragEnter事件處理函數(shù)中執(zhí)行下列處理:

          1.先使用GetDataPresent方法來檢查被拖曳的數(shù)據(jù)是否為純文字(DataFormats.Text)。如果不是純文字的話,便將Effect屬性設(shè)定成DragDropEffects.None表示置放目標(biāo)不接受數(shù)據(jù);如果是純文字的話,則繼續(xù)進(jìn)行后續(xù)處理。

          2.檢查Ctrl鍵是否被按下。如果Ctrl鍵被按下的話,便將Effect屬性設(shè)定成DragDropEffects.Copy,表示復(fù)制數(shù)據(jù)到置放目標(biāo)中,此時鼠標(biāo)指針將會顯示成復(fù)制指針圖標(biāo);如果Ctrl鍵沒有被按下的話,便將Effect屬性設(shè)定成DragDropEffects.Move,表示移動數(shù)據(jù)到置放目標(biāo)中。

          我們會于置放目標(biāo)(也就是右側(cè)下方的TextBox控件)的DragDrop事件處理函數(shù)中執(zhí)行下列處理:
          1.使用GetData方法從DataObject對象中提取被拖曳的文字并將它賦給置放目標(biāo)。
          2.判斷Ctrl鍵是否被按下。如果Ctrl鍵沒有被按下,表示要執(zhí)行移動操作,此時會移除來源文字以便營造出移動文字的效果。
          關(guān)鍵詞:VS.NET