
Nixforest
Collaborators
Tham gia ngày: Jun 2010
Bài g i:ử 23
C p đ :ấ ộ 6
Đi m:ể 299
WPF Tutorial - S d ng Custom Cursorử ụ
WPF Tutorial - S d ng Custom Cursorử ụ
Các b n có th xem bài vi t v s d ng Custom Cursor trong WinForm ạ ể ế ề ử ụ đâyở. Bài h ng d nướ ẫ
này cũng có nhi u v n đ t ng t , cho nên mình nghĩ là b n nên xem qua nó tr c.ề ấ ề ươ ự ạ ướ
Th t s là t o và s d ng m t con tr trong ậ ự ạ ử ụ ộ ỏ WPF khó khăn h n r t nhi u so v i trongơ ấ ề ớ
WinForm. Đi u này là do m t v n đ duy nh t - đó là WPF không dùng ề ộ ấ ề ấ GDI, nh ng con trư ỏ
thì l i dùng. Con tr là m t thành ph n quan tr ng trong Window (nó c n cho t t c các ngạ ỏ ộ ầ ọ ầ ấ ả ứ
d ng, h tr ng i dùng thao tác v i H đi u hành), nh ng l i ích mà nó mang l i là đi uụ ỗ ợ ườ ớ ệ ề ữ ợ ạ ề
không th ch i cãi, nh ng nó v n là đ i t ng GDI. Cho nên ta c n ph i v t qua ranh gi iể ố ư ẫ ố ượ ầ ả ượ ớ
này đ có th làm gì đó đ c bi t v i con tr trong ể ể ặ ệ ớ ỏ WPF.
WPF v n h tr nh ng ẫ ỗ ợ ữ cursor chu n, nh ng khi b n mu n t o m t hình v gì đ y choẩ ư ạ ố ạ ộ ẽ ấ
cursor, ph i làm nhi u vi c đ y. ả ề ệ ấ
Đ u tiên, b n nh r ng, n u mu n t o m t con tr trong ầ ạ ớ ằ ế ố ạ ộ ỏ WinForm, b n ph i dùng m t sạ ả ộ ố
code nh sau:ư
PHP Code:
IntPtr curPtr;
/* CurPtr gets set to
a pointer to an icon */
Cursor myCur = new Cursor(curPtr);
Nh ng trong WPF, nó r t khác. Trong WinForm, đ i t ng Cursor làư ấ ố ượ
System.Windows.Forms.Cursor, còn trong WPF, nó là System.Windows.Input.Cursor, và
Constructor c a class này ko h tr đ i s nào là ủ ỗ ợ ố ố IntPtr c . Nh ng cũng có m t cách t ng tả ư ộ ươ ự
nh trên:ư
PHP Code:
IntPtr ptr;
/* CurPtr gets set to
a pointer to an icon */
SafeFileHandle handle = new SafeFileHandle(ptr, true);
Cursor myCur = System.Windows.Interop.CursorInteropHelper.Create(handle);
Chúng ta s convert m t đ i t ng ẽ ộ ố ượ IntPtr sang m t đ i t ng SafeHandle (SafeFileHandle kộ ố ượ ế
th a t SafeHandle - b n không th t o m t đ i t ng SafeHandle, vì nó là m t ừ ừ ạ ể ạ ộ ố ượ ộ abstract
class). Sau đó b n kh i t o Cursor t ph ng th cạ ở ạ ừ ươ ứ
System.Windows.Interop.CursorInteropHelper.Create v i đ i s là đ i t ng SafeHandle đó.ớ ố ố ố ượ
Chúng ta liên k t code các ph n trên, s có m t l p nh sau:ế ầ ẽ ộ ớ ư
PHP Code:

using System;
using System.Windows.Interop;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Windows.Input;
namespace WPFCursorTest
{
public class CursorHelper
{
private struct IconInfo
{
public bool fIcon;
public int xHotspot;
public int yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
}
[DllImport("user32.dll")]
private static extern IntPtr CreateIconIndirect(ref IconInfo icon);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
public static Cursor CreateCursor(System.Drawing.Bitmap bmp, int xHotSpot,
int yHotSpot)
{
IconInfo tmp = new IconInfo();
GetIconInfo(bmp.GetHicon(), ref tmp);
tmp.xHotspot = xHotSpot;
tmp.yHotspot = yHotSpot;
tmp.fIcon = false;
IntPtr ptr = CreateIconIndirect(ref tmp);
SafeFileHandle handle = new SafeFileHandle(ptr, true);
return CursorInteropHelper.Create(handle);
}
}
}
B n c n l u ý r ng chúng ta đang s d ng m t đ i t ng System.Drawing.Bitmap đây (b nạ ầ ư ằ ử ụ ộ ố ượ ở ạ
nên Add Reference th vi n System.Drawing đ có th s d ng nó). Đây là m t đ i t ngư ệ ể ể ử ụ ộ ố ượ
Bitmap d ng GDI cũ - m t khái ni m n m ngoài các l p WPF. M c đ nh WPF không s d ngạ ộ ệ ằ ớ ặ ị ử ụ
th vi n System.Drawing cho nên b n c n ph i Add chúng vào (ư ệ ạ ầ ả Project/ Add Reference...).
Mình đã th , khá khó, đ tìm ra m t cách t o m t con tr trong WPF mà không c n ph i d aử ể ộ ạ ộ ỏ ầ ả ự
vào System.Drawing.Bitmap. Mình c n ph i nh n đ c m t con tr (ầ ả ậ ượ ộ ỏ Pointer ch không ph iứ ả
Cursor) Icon tr ra ngoài bitmap (nh hàm GetHicon), nh ng đ i t ng bitmap trong WPF l iỏ ư ư ố ượ ạ
không th t o ra m t Pointer nào c .ể ạ ộ ả

Nh ng ko ph i đã h t hi v ng! Hãy th v i m t overload c a ph ng th c CreateCursor d iư ả ế ọ ử ớ ộ ủ ươ ứ ướ
đây xem:
PHP Code:
public static Cursor CreateCursor(UIElement element, int xHotSpot, int yHotSpot)
{
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(0, 0, element.DesiredSize.Width,
element.DesiredSize.Height));
RenderTargetBitmap rtb = new RenderTargetBitmap((int)element.DesiredSize.Width,
(int)element.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32);
rtb.Render(element);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
MemoryStream ms = new MemoryStream();
encoder.Save(ms);
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ms);
ms.Close();
ms.Dispose();
Cursor cur = InternalCreateCursor(bmp, xHotSpot, yHotSpot);
bmp.Dispose();
return cur;
}
đây, mình dùng m t Ở ộ UIElement - c t lõi c a c u trúc WPF. Mình đo đ c và s p x p nó đố ủ ấ ạ ắ ế ể
ch c ch n nó đ c tr v nh ng giá tr đúng, và sau đó mình "t o m t b c nh t nó". Mìnhắ ắ ượ ả ề ữ ị ạ ộ ứ ả ừ
th c hi n b ng cách t o m t đ i t ng RenderTargetBitmap. Đây là m t l p đ i t ng trongự ệ ằ ạ ộ ố ượ ộ ớ ố ượ
WPF cho phép b n l y m t đ i t ng ạ ấ ộ ố ượ UIElement và v nó lên m t bitmap - nh ng nh là,ẽ ộ ư ớ
đây là bitmap c a WPF (chính xác là m t đ i t ngủ ộ ố ượ
System.Windows.Media.Imaging.RenderTargetBitmap). Nó không gi ng nh đ i t ngố ư ố ượ
System.Drawing.Bitmap. Mình hi u ch nh kích th c cho nó, sau đó render UIElement trênệ ỉ ướ
bitmap đó.
Bây gi mình có m t đ i t ng RenderTargetBitmap trong tay, mình mu n t o m t đ i t ngờ ộ ố ượ ố ạ ộ ố ượ
System.Drawing.Bitmap. Microsoft hoàn toàn có kh năng làm đi u này d dàng h n (nh ngả ề ễ ơ ư
h không làm), và mình th c s khó ch u v nó. Có m t vài ph ng pháp cho phép b nọ ự ự ị ề ộ ươ ạ
chuy n t đ i t ng System.Drawing.Bitmap sang đ i t ng bitmap c a WPF, nh ng ng cể ừ ố ượ ố ượ ủ ư ượ
l i thì hoàn toàn không. Ít nh t là mình ch a th tìm ra. N u có b n nào bi t nh ng ph ngạ ấ ư ể ế ạ ế ữ ươ
th c t ng t nh v y (ho c t t h n cách mình đã miêu t ), hãy chia s ^_^.ứ ươ ự ư ậ ặ ố ơ ả ẻ
Mình dùng m t Encoder, và mã hóa bitmap (ộRenderTargetBitmap) nh m t đ i t ng PNGư ộ ố ượ
(b n có th mã hóa nh th nào tùy thích). Sau đó, mình t o m t MemoryStream và l u mãạ ể ư ế ạ ộ ư
c a bitmap (đã đ c mã hóa) vào trong stream đó. Ti p theo mình t o m t đ i t ngủ ượ ế ạ ộ ố ượ
System.Drawing.Bitmap v i Contructor có tham s là m t MemoryStream. Nên nh ph i gi iớ ố ộ ớ ả ả
phóng các đ i t ng không dùng đ n n a.ố ượ ế ữ
Toàn b code chúng ta c n đây:ộ ầ ở
PHP Code:
using System;
using System.Windows.Interop;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Windows.Input;
using System.Windows.Media;

using System.Windows.Media.Imaging;
using System.IO;
using System.Windows;
namespace WPFCursorTest
{
public class CursorHelper
{
private struct IconInfo
{
public bool fIcon;
public int xHotspot;
public int yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
}
[DllImport("user32.dll")]
private static extern IntPtr CreateIconIndirect(ref IconInfo icon);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
private static Cursor InternalCreateCursor(System.Drawing.Bitmap bmp,
int xHotSpot, int yHotSpot)
{
IconInfo tmp = new IconInfo();
GetIconInfo(bmp.GetHicon(), ref tmp);
tmp.xHotspot = xHotSpot;
tmp.yHotspot = yHotSpot;
tmp.fIcon = false;
IntPtr ptr = CreateIconIndirect(ref tmp);
SafeFileHandle handle = new SafeFileHandle(ptr, true);
return CursorInteropHelper.Create(handle);
}
public static Cursor CreateCursor(UIElement element, int xHotSpot, int yHotSpot)
{
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(0, 0, element.DesiredSize.Width,
element.DesiredSize.Height));
RenderTargetBitmap rtb = new RenderTargetBitmap((int)element.DesiredSize.Width,
(int)element.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32);
rtb.Render(element);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
MemoryStream ms = new MemoryStream();
encoder.Save(ms);

System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(ms);
ms.Close();
ms.Dispose();
Cursor cur = InternalCreateCursor(bmp, xHotSpot, yHotSpot);
bmp.Dispose();
return cur;
}
}
}
Bây gi là cách s d ng class:ờ ử ụ
PHP Code:
public partial class CursorTest : Window
{
public CursorTest()
{
InitializeComponent();
TextBlock tb = new TextBlock();
tb.Text = "{ } Switch On The Code";
tb.FontSize = 10;
tb.Foreground = Brushes.Green;
this.Cursor = CursorHelper.CreateCursor(tb, 5, 5);
}
}
Và k t qu là:ế ả
Translate from http://www.switchonthecode.com
__________________
Try my best...