本文內(nèi)容
- WPF 中的拖放支持
- 數(shù)據(jù)傳輸
- 拖放事件
- 實(shí)現(xiàn)拖放
- 拖放示例
本主題概述 Windows Presentation Foundation (WPF) 應(yīng)用程序中的拖放支持。 拖放通常指一種數(shù)據(jù)傳輸方法:使用鼠標(biāo)(或一些其他指針設(shè)備)選擇一個或多個對象,將其拖至用戶界面 (UI) 中的某些所需拖放目標(biāo)之上并放置。
1、WPF 中的拖放支持
拖放操作通常涉及兩個參與方:拖動對象所源自的拖動源和接收放置對象的拖放目標(biāo)。 拖動源和放置目標(biāo)可能是相同應(yīng)用程序或不同應(yīng)用程序中的 UI 元素。
可借助拖放操縱的對象的類型和數(shù)量是完全任意的。 例如,文件、文件夾和內(nèi)容選擇是利用拖放操作操縱的一些常見對象。
拖放操作期間執(zhí)行的特定操作特定于應(yīng)用程序,并且通常由上下文而定。 例如,將選擇的文件從一個文件夾拖動至相同存儲設(shè)備上的另一個文件夾將默認(rèn)移動文件;而將文件從通用命名約定 (UNC) 共享拖動至本地文件夾將默認(rèn)復(fù)制文件。
WPF 提供的拖放設(shè)施擁有高度的靈活性并可自定義,以便支持各種拖放方案。 拖放支持在單個應(yīng)用程序內(nèi)或不同應(yīng)用程序之間操作對象。 也完全支持 WPF 應(yīng)用程序和其它 Windows 應(yīng)用程序之間的拖放。
在 WPF 中,任何?UIElement?或?ContentElement?都可以參與拖放。 拖放操作所需的事件和方法是在?DragDrop?類中定義的。?UIElement?和?ContentElement?類包含?DragDrop?附加事件的別名,從而在?UIElement?或?ContentElement?作為基元素繼承時,這些事件出現(xiàn)在類成員列表中。 附加到這些事件的事件處理程序會附加到基礎(chǔ)?DragDrop?附加事件,并接收相同的事件數(shù)據(jù)實(shí)例。?
2、數(shù)據(jù)傳輸
拖放屬于廣義的數(shù)據(jù)傳輸。 數(shù)據(jù)傳輸包括拖放和復(fù)制粘貼操作。 拖放操作類似于用于借助系統(tǒng)剪貼板將數(shù)據(jù)從一個對象或應(yīng)用程序傳輸?shù)搅硪粋€對象或應(yīng)用程序的復(fù)制粘貼或剪切和粘貼操作。 這兩種類型的操作均要求:
-
提供數(shù)據(jù)的源對象。
-
用于臨時存儲傳輸?shù)臄?shù)據(jù)的方法。
-
接收數(shù)據(jù)的目標(biāo)對象。
在復(fù)制粘貼操作中,系統(tǒng)剪貼板用于臨時存儲傳輸?shù)臄?shù)據(jù);在拖放操作中,DataObject?用于存儲數(shù)據(jù)。 從概念上講,數(shù)據(jù)對象由一對或多對包含實(shí)際數(shù)據(jù)的?Object?和對應(yīng)的數(shù)據(jù)格式標(biāo)識符組成。
拖動源通過調(diào)用靜態(tài)?DragDrop.DoDragDrop?方法和向其傳遞傳輸?shù)臄?shù)據(jù)來啟動拖放操作。 如有必要,DoDragDrop?方法將使?DataObject?中的數(shù)據(jù)自動換行。 為了更好地控制數(shù)據(jù)格式,可將?DataObject?中的數(shù)據(jù)換行,然后再將其傳遞至?DoDragDrop?方法。 拖放目標(biāo)負(fù)責(zé)從?DataObject?中提取數(shù)據(jù)。?
拖放操作的源和目標(biāo)均為 UI 元素;然而,實(shí)際正在傳輸?shù)臄?shù)據(jù)通常不具有可視表示形式。 可以編寫代碼來提供拖動的數(shù)據(jù)的可視表示形式(比如當(dāng)在 Windows 資源管理器中拖動文件時會出現(xiàn)這種情況)。 默認(rèn)情況下,通過更改光標(biāo)將反饋提供給用戶,以便表示拖放操作將對數(shù)據(jù)產(chǎn)生的影響,例如將移動數(shù)據(jù)還是復(fù)制數(shù)據(jù)。
拖放效果
拖放操作對傳輸?shù)臄?shù)據(jù)可具有不同的效果。 例如,可以復(fù)制數(shù)據(jù),或者可以移動數(shù)據(jù)。 WPF 定義可用于指定拖放操作效果的?DragDropEffects?枚舉。 在拖動源中,可以指定源在?DoDragDrop?方法中允許的效果。 在拖放目標(biāo)中,可以指定目標(biāo)在?Effects?類的?DragEventArgs?屬性的中預(yù)期的效果。 當(dāng)拖放目標(biāo)指定其在?DragOver?事件中的預(yù)期效果時,該信息將被傳遞回?GiveFeedback?事件中的拖動源。 拖動源則使用此信息通知用戶拖放目標(biāo)想要對數(shù)據(jù)產(chǎn)生的效果。 放置數(shù)據(jù)時,拖放目標(biāo)指定其在?Drop?事件中的實(shí)際效果。 該信息會作為?DoDragDrop?方法的返回值傳遞回拖動源。 如果拖放目標(biāo)返回并不在?allowedEffects
?拖動源列表中的效果,那么將取消拖放操作,且不會進(jìn)行任何數(shù)據(jù)傳輸。
請務(wù)必記住,在 WPF 中,DragDropEffects?值僅用于提供有關(guān)拖放操作效果的拖動源和拖放目標(biāo)之間的通信。 拖放操作的實(shí)際效果取決于你在應(yīng)用程序中編寫的相應(yīng)代碼。
例如,拖放目標(biāo)可以指定在其中放置數(shù)據(jù)的效果是移動數(shù)據(jù)。 然而,若要移動數(shù)據(jù),必須將數(shù)據(jù)添加到目標(biāo)元素并從源元素中刪除數(shù)據(jù)。 源元素可能指示允許移動數(shù)據(jù),但是如果沒有提供從源元素中刪除數(shù)據(jù)的代碼,那么最終結(jié)果將為復(fù)制但不刪除數(shù)據(jù)。
3、拖放事件
拖放操作支持事件驅(qū)動模型。 拖動源和拖放目標(biāo)都使用一組標(biāo)準(zhǔn)的事件來處理拖放操作。 下表總結(jié)了標(biāo)準(zhǔn)的拖放事件。 它們是?DragDrop?類中的附加事件。?
拖動源事件
展開表
事件 | 總結(jié) |
---|---|
GiveFeedback | 此事件在拖放操作期間持續(xù)發(fā)生,并且使放置源能夠向用戶提供反饋信息。 通常通過更改鼠標(biāo)指針外觀來指示拖放目標(biāo)允許的效果這一方式來提供這種反饋。 這是冒泡事件。 |
QueryContinueDrag | 此事件于拖放操作期間鍵盤或鼠標(biāo)按鈕狀態(tài)發(fā)生變化時發(fā)生,并使放置源能夠根據(jù)鍵/按鈕狀態(tài)取消拖放操作。 這是冒泡事件。 |
PreviewGiveFeedback | GiveFeedback?的隧道版本。 |
PreviewQueryContinueDrag | QueryContinueDrag?的隧道版本。 |
拖放目標(biāo)事件
展開表
事件 | 總結(jié) |
---|---|
DragEnter | 將對象拖到拖放目標(biāo)的邊界中時發(fā)生此事件。 這是冒泡事件。 |
DragLeave | 將對象拖出拖放目標(biāo)邊界時發(fā)生此事件。 這是冒泡事件。 |
DragOver | 在拖放目標(biāo)的邊界內(nèi)拖動(移動)對象時會持續(xù)發(fā)生此事件。 這是冒泡事件。 |
Drop | 將對象放置在拖放目標(biāo)上時發(fā)生此事件。 這是冒泡事件。 |
PreviewDragEnter | DragEnter?的隧道版本。 |
PreviewDragLeave | DragLeave?的隧道版本。 |
PreviewDragOver | DragOver?的隧道版本。 |
PreviewDrop | Drop?的隧道版本。 |
若要處理對象實(shí)例的拖放事件,請為上表中所列的事件添加處理程序。 若要處理類級別的拖放事件,請重寫相應(yīng)的虛擬 On*Event 和 On*PreviewEvent 方法。?
4、實(shí)現(xiàn)拖放
UI 元素可以是拖動源、拖放目標(biāo)或兩者均可。 若要實(shí)現(xiàn)基本拖放,請編寫用于啟動拖放操作和處理放置的數(shù)據(jù)的代碼。 可以通過處理可選拖放事件增強(qiáng)拖放體驗(yàn)。
若要實(shí)現(xiàn)基本拖放,將完成以下任務(wù):
-
標(biāo)識將作為拖動源的元素。 拖動源可以是?UIElement?或?ContentElement。
-
在將啟動拖放操作的拖動源上創(chuàng)建事件處理程序。 此事件通常是?MouseMove?事件。
-
在拖動源事件處理程序中,調(diào)用?DoDragDrop?方法啟動拖放操作。 在?DoDragDrop?調(diào)用中,指定拖動源、要傳輸?shù)臄?shù)據(jù)和允許的效果。
-
標(biāo)識將作為拖放目標(biāo)的元素。 拖放目標(biāo)可以是?UIElement?或?ContentElement。
-
在拖放目標(biāo)上,將?AllowDrop?屬性設(shè)置為?
true
。 -
在拖放目標(biāo)中,創(chuàng)建?Drop?事件處理程序以處理放置的數(shù)據(jù)。
-
在?Drop?事件處理程序中,利用?DragEventArgs?和?GetDataPresent?方法提取?GetData?中的數(shù)據(jù)。
-
在?Drop?事件處理程序中,使用數(shù)據(jù)來執(zhí)行所需的拖放操作。
可以通過創(chuàng)建自定義?DataObject?和處理可選拖動源和拖放目標(biāo)事件來增加拖放實(shí)現(xiàn),如以下任務(wù)中所示:
-
若要傳輸自定義數(shù)據(jù)或多個數(shù)據(jù)項(xiàng),請創(chuàng)建一個?DataObject以傳遞至?DoDragDrop?方法。
-
若要在拖動過程中執(zhí)行其他操作,請?zhí)幚硗戏拍繕?biāo)上的?DragEnterDragOver?和?DragLeave?事件。
-
若要更改鼠標(biāo)指針外觀,請?zhí)幚硗蟿釉瓷系?GiveFeedback?事件。
-
若要更改取消拖放操作的方式,請?zhí)幚硗蟿釉瓷系?QueryContinueDrag?事件。
5、拖放示例
本節(jié)介紹如何實(shí)現(xiàn)?Ellipse?元素的拖放。?Ellipse?既是拖動源也是拖放目標(biāo)。 傳輸?shù)臄?shù)據(jù)是橢圓形的?Fill?屬性的字符串表示形式。 下面的 XAML 展示?Ellipse?元素和它處理的拖放相關(guān)事件。?
<Ellipse Height="50" Width="50" Fill="Green"
MouseMove="ellipse_MouseMove"
GiveFeedback="ellipse_GiveFeedback"
AllowDrop="True"
DragEnter="ellipse_DragEnter" DragLeave="ellipse_DragLeave"
DragOver="ellipse_DragOver" Drop="ellipse_Drop" />
5.1 使元素作為拖動源
拖動源對象用于:
-
標(biāo)識拖動發(fā)生的時候。
-
啟動拖放操作。
-
標(biāo)識要傳輸?shù)臄?shù)據(jù)。
-
指定允許拖放操作對傳輸?shù)臄?shù)據(jù)產(chǎn)生的效果。
拖動源還可能針對允許的操作(移動、復(fù)制、無)向用戶提供反饋,并且可以根據(jù)額外用戶輸入(如拖動過程中按 ESC 鍵)取消拖放操作。
你的應(yīng)用程序負(fù)責(zé)確定發(fā)生拖動的時間,然后通過調(diào)用?DoDragDrop?方法啟動拖放操作。 通常情況下,這是在按下鼠標(biāo)按鈕的同時,要拖動的元素上發(fā)生?MouseMove?事件時。 下面的示例顯示了如何從?Ellipse?元素的?MouseMove?事件處理程序中啟動拖放操作,以將其作為拖動源。 傳輸?shù)臄?shù)據(jù)是橢圓形的?Fill?屬性的字符串表示形式。
private void ellipse_MouseMove(object sender, MouseEventArgs e)
{
Ellipse ellipse = sender as Ellipse;
if (ellipse != null && e.LeftButton == MouseButtonState.Pressed)
{
DragDrop.DoDragDrop( ellipse,
ellipse.Fill.ToString(),
DragDropEffects.Copy);
}
}
在?MouseMove?事件處理程序中,調(diào)用?DoDragDrop?方法啟動拖放操作。?DoDragDrop?方法采用三個參數(shù):
-
dragSource
?– 引用作為傳輸?shù)臄?shù)據(jù)的源的依賴項(xiàng)對象;通常是?MouseMove?事件的源。 -
data
?- 包含傳輸?shù)臄?shù)據(jù)(包裝在?DataObject?中)的對象。 -
allowedEffects
?- 指定拖放操作允許的效果的?DragDropEffects?枚舉值之一。
任何可序列化對象都可以在?data
?參數(shù)中傳遞。 如果數(shù)據(jù)尚未包裝在?DataObject?中,則它將自動包裝在一個新的?DataObject?中。 若要傳遞多個數(shù)據(jù)項(xiàng),必須自行創(chuàng)建?DataObject,并將其傳遞到?DoDragDrop?方法。?
allowedEffects
?參數(shù)用于指定拖動源允許拖放目標(biāo)對傳輸?shù)臄?shù)據(jù)進(jìn)行什么操作。 拖動源公共值為?CopyMove?和All。
?備注
拖放目標(biāo)也能夠指定其對放置的數(shù)據(jù)的預(yù)期效果。 例如,如果拖放目標(biāo)不能識別要放置的數(shù)據(jù)類型,則可以通過將其允許的效果設(shè)置為?None?來拒絕數(shù)據(jù)。 通常在其?DragOver?事件處理程序中進(jìn)行此操作。
拖動源還可以可選地處理?GiveFeedback?和?QueryContinueDrag?事件。 這些事件都具有使用的默認(rèn)處理程序,除非將事件標(biāo)記為已處理。 通常將忽略這些事件,除非有更改其默認(rèn)行為的特定需要。
對拖動源進(jìn)行拖動時,持續(xù)引發(fā)?GiveFeedback?事件。 此事件的默認(rèn)處理程序會檢查拖動源是否在有效放置目標(biāo)之上。 如果是,它會檢查拖放目標(biāo)的允許的效果。 然后向最終用戶提供有關(guān)允許的放置效果的反饋。 通常通過將鼠標(biāo)光標(biāo)更改為非放置、復(fù)制或移動光標(biāo)實(shí)現(xiàn)此操作。 僅在需要使用自定義光標(biāo)向用戶提供反饋時處理此事件。 在處理此事件時,請務(wù)必將其標(biāo)記為“已處理”,以便默認(rèn)處理程序不會替代你的處理程序。
對拖動源進(jìn)行拖動時,持續(xù)引發(fā)?QueryContinueDrag?事件。 你可以根據(jù) ESC、SHIFT、CTRL 和 ALT 鍵以及鼠標(biāo)按鈕的狀態(tài)處理此事件,以確定結(jié)束拖放操作的操作。 此事件的默認(rèn)處理程序在按下 ESC 鍵后取消拖放操作,并且在釋放鼠標(biāo)按鈕后放置數(shù)據(jù)。
?注意
在拖放操作過程中,將持續(xù)引發(fā)這些事件。 因此,應(yīng)避免事件處理程序中的資源密集型任務(wù)。 例如,每次引發(fā)?GiveFeedback?事件時,請使用緩存的光標(biāo),而不是創(chuàng)建新光標(biāo)。
5.2 使元素作為拖放目標(biāo)
作為拖放目標(biāo)的對象用于:
-
指定其是有效的拖放目標(biāo)。
-
當(dāng)它拖動到目標(biāo)之上時,向拖動源作出響應(yīng)。
-
檢查傳輸?shù)臄?shù)據(jù)是否是它可以接收的格式。
-
處理已放置的數(shù)據(jù)。
若要指定一個元素是拖放目標(biāo),請將其?AllowDrop?屬性設(shè)置為?true
。 然后,元素中將引發(fā)拖放目標(biāo)事件,以便處理這些事件。 在拖放操作期間,拖放目標(biāo)上將依次發(fā)生以下事件:
-
DragEnter
-
DragOver
-
DragLeave?或?Drop
將數(shù)據(jù)拖到拖放目標(biāo)的邊界中時發(fā)生?DragEnter?事件。 通常,如果適用于你的應(yīng)用程序,可處理此事件,以便提供拖放操作效果預(yù)覽。 請勿設(shè)置?DragEventArgs.Effects?事件中的?DragEnter?屬性,因?yàn)樵?DragOver?事件中該屬性將被覆蓋。
下面的示例演示?DragEnter?元素的?Ellipse?事件處理程序。 此代碼通過保存當(dāng)前的?Fill?畫筆預(yù)覽拖放操作的效果。 然后,它使用?GetDataPresent?方法來檢查是否已將?DataObject?拖動到包含可以轉(zhuǎn)換為?Brush?的字符串?dāng)?shù)據(jù)的橢圓上方。 如果是,則使用?GetData?方法提取數(shù)據(jù)。 然后將其轉(zhuǎn)換為?Brush?并應(yīng)用于橢圓。 在?DragLeave?事件處理程序中還原更改。 如果數(shù)據(jù)無法轉(zhuǎn)換為?Brush,則不執(zhí)行任何操作。
private Brush _previousFill = null;
private void ellipse_DragEnter(object sender, DragEventArgs e)
{
Ellipse ellipse = sender as Ellipse;
if (ellipse != null)
{
// Save the current Fill brush so that you can revert back to this value in DragLeave.
_previousFill = ellipse.Fill;
// If the DataObject contains string data, extract it.
if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
// If the string can be converted into a Brush, convert it.
BrushConverter converter = new BrushConverter();
if (converter.IsValid(dataString))
{
Brush newFill = (Brush)converter.ConvertFromString(dataString);
ellipse.Fill = newFill;
}
}
}
}
將數(shù)據(jù)拖動到拖放目標(biāo)上方時持續(xù)發(fā)生?DragOver?事件。 此事件和拖動源上的?GiveFeedback?事件成對出現(xiàn)。 在?DragOver?事件處理程序中,通常使用?GetDataPresent?和?GetData?方法來檢查傳輸?shù)臄?shù)據(jù)是否是拖放目標(biāo)可以處理的格式。 還可以檢查是否已按下修改鍵,這通常指示用戶想進(jìn)行移動操作還是復(fù)制操作。 執(zhí)行這些檢查后,設(shè)置?DragEventArgs.Effects?屬性以通知拖動源放置數(shù)據(jù)將產(chǎn)生的效果。 拖動源收到?GiveFeedback?事件參數(shù)中的此信息,并且可以設(shè)置相應(yīng)的光標(biāo)以向用戶提供反饋。
下面的示例演示?DragOver?元素的?Ellipse?事件處理程序。 此代碼檢查是否已將?DataObject?拖動到包含可以轉(zhuǎn)換為?Brush?的字符串?dāng)?shù)據(jù)的橢圓上方。 如果是,它會將?DragEventArgs.Effects?屬性設(shè)置為?Copy。 這將向拖動源指示可以將數(shù)據(jù)復(fù)制到橢圓。 如果數(shù)據(jù)無法轉(zhuǎn)換為?Brush,則將?DragEventArgs.Effects?屬性設(shè)置為?None。 這將向拖動源指示橢圓不是數(shù)據(jù)的有效拖放目標(biāo)。
private void ellipse_DragOver(object sender, DragEventArgs e)
{
e.Effects = DragDropEffects.None;
// If the DataObject contains string data, extract it.
if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
// If the string can be converted into a Brush, allow copying.
BrushConverter converter = new BrushConverter();
if (converter.IsValid(dataString))
{
e.Effects = DragDropEffects.Copy | DragDropEffects.Move;
}
}
}
將數(shù)據(jù)拖出目標(biāo)邊界而未放置時,發(fā)生?DragLeave?事件。 可以處理此事件,以便撤銷在?DragEnter?事件處理程序中進(jìn)行的一切操作。
下面的示例演示?DragLeave?元素的?Ellipse?事件處理程序。 此代碼通過將保存的?Brush?應(yīng)用到橢圓來撤銷?DragEnter?事件處理程序中執(zhí)行的預(yù)覽。
private void ellipse_DragLeave(object sender, DragEventArgs e)
{
Ellipse ellipse = sender as Ellipse;
if (ellipse != null)
{
ellipse.Fill = _previousFill;
}
}
數(shù)據(jù)放置在拖放目標(biāo)上方時,發(fā)生?Drop?事件;默認(rèn)情況下,釋放鼠標(biāo)按鈕時,發(fā)生此事件。 在?Drop?事件處理程序中,使用?GetData?方法提取?DataObject?中的傳輸?shù)臄?shù)據(jù)并執(zhí)行應(yīng)用程序所需的任何數(shù)據(jù)處理。?Drop?事件結(jié)束拖放操作。文章來源:http://www.zghlxwxcb.cn/news/detail-812765.html
下面的示例演示?Drop?元素的?Ellipse?事件處理程序。 此代碼應(yīng)用拖放操作的效果,并且它類似于?DragEnter?事件處理程序中的代碼。 它會檢查是否將?DataObject?拖動到包含可以轉(zhuǎn)換為?Brush?的字符串?dāng)?shù)據(jù)的橢圓上方。 如果是,將?Brush?應(yīng)用于橢圓。 如果數(shù)據(jù)無法轉(zhuǎn)換為?Brush,則不執(zhí)行任何操作。文章來源地址http://www.zghlxwxcb.cn/news/detail-812765.html
private void ellipse_Drop(object sender, DragEventArgs e)
{
Ellipse ellipse = sender as Ellipse;
if (ellipse != null)
{
// If the DataObject contains string data, extract it.
if (e.Data.GetDataPresent(DataFormats.StringFormat))
{
string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
// If the string can be converted into a Brush,
// convert it and apply it to the ellipse.
BrushConverter converter = new BrushConverter();
if (converter.IsValid(dataString))
{
Brush newFill = (Brush)converter.ConvertFromString(dataString);
ellipse.Fill = newFill;
}
}
}
}
到了這里,關(guān)于【W(wǎng)PF.NET開發(fā)】WPF中的拖放的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!