2014-05-02 82 views
3

我試圖找出如何實現WPF中的內容(我相信如此 - 沒有WPF的經驗)「拖曳裝飾者」。我一直在尋找,現在一兩天的嘗試不同的提出瞭解決方案,但沒有人看起來挺像我後。我希望儘可能地接近Windows的原生外觀和感覺。WinForms中的WPF裝飾者

這是半透明的圖像,我們在上面和鼠標指針的左側略微看到,當我們拖動在Firefox或BigBlueE™在IE地址欄中全球等

雙擊和拖拽在這個頁面上的一個字,你會明白我的意思。光標仍然是一個Cursors.No直到TextBox遇到 - 在這一點上,我們看到的文本的圖形表示被拖動。顯示光標的標準移動/複製可視指示器(右下方的小灰色方塊;複製時爲加號)。

Sheridan說here他舔了這個問題;我希望能聽到他的提示。

無論是VB還是C#建議都可以,但WinForms是必須的。

如果我能指出正確的方向,我可以從那裏拿走它。

謝謝。


更新:我已經在我的首選解決方案,here解決。我知道,我本來要求光標的本地移動/複製指標原地不動,但這裏的SetDropDescription()功能是如此的高興,我改變了主意,決定用它來而不是去。這裏的WPF樣品的外觀運行時,如:

DragDropSample

這是相當不錯的。這都是Interop,所以它應該轉化爲WinForms。

+0

更新:謝里登回覆(謝謝你謝里登),以澄清他的解決方案是在WPF,而不是WinForms。 – InteXX

+0

@HighCore,這個功能在WPF之前就存在於Windows中,所以是的,我很確定它可以用WinForms –

+0

@InteXX完成我很抱歉這不是我的意圖冒犯任何人。沒有WPF不是「本地Windows功能的包裝」 - 它更多的是DirectX上的包裝。我的觀點是人們不會用winforms做東西(VS工具箱中的默認東西除外)。如果你真的需要這個,請使用ElementHost或其他東西進行WPF互操作。 –

回答

3

有可能實現與自定義光標這種效果。您可以按照this answer中所述創建光標。當您啓動拖動操作,創建光標,並在GiveFeedback事件,設置Cursor.Current到光標和e.UseDefaultCursors爲false。

這裏的(使用LINQPad)一個完整的例子:

https://gist.github.com/thomaslevesque/837d1a8295b33be2b404

+0

嗨托馬斯,謝謝。儘管如此,還不夠。在我的搜索中,我找到了幾個這樣的變體 - 對不起,我是新的,仍然在學習如何在SO上詞組問題 - 但它不會保留標準的複製/移動視覺指示器。現在......說......我發現了比我想的更好的東西,[這裏](http://blogs.msdn.com/b/adamroot/archive/2008/02/19/shell-style -drag和拖放式淨部分3.aspx)。我非常喜歡'SetDropDescription()'功能。它在C#WPF中;我不應該有太多的麻煩轉換爲VB的WinForms ...可能比切換到WPF更麻煩,你認爲? ;-) – InteXX

+0

@InteXX,看起來像一個理想的解決方案,但它似乎也相當複雜...無論如何,切換到WPF和使用裝飾並不會產生相同的效果:裝飾只能在窗口中可見。 –

+0

我同意你的複雜性,但至少對於手頭的需求來說,這是值得的。我感謝你的貢獻。 – InteXX

1

更多的研究:事實證明,我們不能安全地使用外殼擴展的解決方案。即使在這段時間之後,殼牌和CLR仍然沒有混用。見here

因此,我決定繪製一個看起來像殼牌圖標的圖像,並使用自定義光標來顯示它們。單調乏味,是的,但必須完成。

這裏是代碼,做成擴展方法,並調整了一些內存泄漏。

Public Module Gdi 
    <Extension()> 
    Public Function ToCursor(Bitmap As Bitmap, HotSpot As Point) As Cursor 
    Dim oInfo As Interop.Structures.IconInfo 
    Dim hIcon As IntPtr 

    oInfo = New Interop.Structures.IconInfo 
    hIcon = Bitmap.GetHicon 

    Interop.Functions.GetIconInfo(hIcon, oInfo) 

    oInfo.HotSpotX = HotSpot.X 
    oInfo.HotSpotY = HotSpot.Y 
    oInfo.IsIcon = False 

    ToCursor = New Cursor(Interop.Functions.CreateIconIndirect(oInfo)) 

    If oInfo.Color <> IntPtr.Zero Then Interop.Functions.DeleteObject(oInfo.Color) 
    If oInfo.Mask <> IntPtr.Zero Then Interop.Functions.DeleteObject(oInfo.Mask) 
    If hIcon <> IntPtr.Zero Then Interop.Functions.DestroyIcon(hIcon) 
    End Function 


    <Extension()> 
    Public Function ToBitmap(Cursor As Cursor) As Bitmap 
    Dim oInfo As Interop.Structures.IconInfo 
    Dim oData As BitmapData 
    Dim hIcon As IntPtr 

    oInfo = New Interop.Structures.IconInfo 
    hIcon = Cursor.Handle 

    Interop.Functions.GetIconInfo(hIcon, oInfo) 

    Using oBitmap As Bitmap = Bitmap.FromHbitmap(oInfo.Color) 
     Interop.Functions.DeleteObject(oInfo.Color) 
     Interop.Functions.DeleteObject(oInfo.Mask) 

     oData = oBitmap.LockBits(New Rectangle(0, 0, oBitmap.Width, oBitmap.Height), ImageLockMode.ReadOnly, oBitmap.PixelFormat) 
     ToBitmap = New Bitmap(oData.Width, oData.Height, oData.Stride, PixelFormat.Format32bppArgb, oData.Scan0) 
     oBitmap.UnlockBits(oData) 
    End Using 
    End Function 
End Module 

Public Class Functions 
    <DllImport("User32")> _ 
    Public Shared Function CreateIconIndirect(ByRef Icon As Structures.IconInfo) As IntPtr 
    End Function 

    <DllImport("User32")> _ 
    Public Shared Function GetIconInfo(Icon As IntPtr, ByRef Info As Structures.IconInfo) As <MarshalAs(UnmanagedType.Bool)> Boolean 
    End Function 

    <DllImport("Gdi32")> _ 
    Public Shared Function DeleteObject(Handle As IntPtr) As Boolean 
    End Function 

    <DllImport("User32", CharSet:=CharSet.Auto)> _ 
    Public Shared Function DestroyIcon(Handle As IntPtr) As Boolean 
    End Function 
End Class 

Namespace Structures 
    Public Structure IconInfo 
    Public IsIcon As Boolean 
    Public HotSpotX As Integer 
    Public HotSpotY As Integer 
    Public Mask As IntPtr 
    Public Color As IntPtr 
    End Structure 
End Namespace 

不幸的是ToBitMap()不適用於低分辨率光標,例如Default。然而,多花一點力氣,它可以使一個體面的形象。也許oBitmap = Icon.FromHandle(Cursor).ToBitmap就足夠了,但產生的圖像質量就留下個人的選擇。